mirror of
https://github.com/falcosecurity/falco.git
synced 2026-04-01 17:42:03 +00:00
Compare commits
44 Commits
fix/workar
...
0.36.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b62b5ccd1 | ||
|
|
cc858f082f | ||
|
|
2996c120c4 | ||
|
|
9eb611609a | ||
|
|
f23b0c1a20 | ||
|
|
7b28b7acec | ||
|
|
aa4899c1e5 | ||
|
|
d454c8a1f4 | ||
|
|
0b48da30ca | ||
|
|
0b761ff1da | ||
|
|
ee56a5c4e4 | ||
|
|
18e340bca8 | ||
|
|
0abef91f5d | ||
|
|
41c304a902 | ||
|
|
fa9c616e7f | ||
|
|
bff920d07f | ||
|
|
df7159554c | ||
|
|
a6403606e5 | ||
|
|
cff980e8b8 | ||
|
|
22344069ed | ||
|
|
90f7e07182 | ||
|
|
f89480ab3a | ||
|
|
e9d2771d72 | ||
|
|
bfabaadab6 | ||
|
|
882e71a67c | ||
|
|
45c55ae4e1 | ||
|
|
80d20bff28 | ||
|
|
db6b15f42c | ||
|
|
38832d99e7 | ||
|
|
ac9af5427b | ||
|
|
60f1b09e17 | ||
|
|
7f33ededa6 | ||
|
|
c65718f7bc | ||
|
|
3c1928dff4 | ||
|
|
9f0cd50b6e | ||
|
|
393825295e | ||
|
|
7c7e54d1bb | ||
|
|
803b5eea06 | ||
|
|
78f32026f2 | ||
|
|
f989fdba52 | ||
|
|
9e3e73c033 | ||
|
|
95e0465309 | ||
|
|
5d49ea77c0 | ||
|
|
4479de5b9e |
4
.github/release_template.md
vendored
4
.github/release_template.md
vendored
@@ -1,5 +1,5 @@
|
||||
[](https://github.com/falcosecurity/libs/releases/tag/LIBSVER)
|
||||
[](https://github.com/falcosecurity/libs/releases/tag/DRIVERVER)
|
||||

|
||||

|
||||
|
||||
| Packages | Download |
|
||||
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
|
||||
9
.github/workflows/ci.yml
vendored
9
.github/workflows/ci.yml
vendored
@@ -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)
|
||||
|
||||
6
.github/workflows/codeql.yaml
vendored
6
.github/workflows/codeql.yaml
vendored
@@ -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
|
||||
|
||||
4
.github/workflows/codespell.yml
vendored
4
.github/workflows/codespell.yml
vendored
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
6
.github/workflows/release.yaml
vendored
6
.github/workflows/release.yaml
vendored
@@ -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 }}
|
||||
|
||||
2
.github/workflows/reusable_build_dev.yaml
vendored
2
.github/workflows/reusable_build_dev.yaml
vendored
@@ -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 }}
|
||||
|
||||
4
.github/workflows/reusable_build_docker.yaml
vendored
4
.github/workflows/reusable_build_docker.yaml
vendored
@@ -32,7 +32,7 @@ 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@v2
|
||||
@@ -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
|
||||
|
||||
25
.github/workflows/reusable_build_packages.yaml
vendored
25
.github/workflows/reusable_build_packages.yaml
vendored
@@ -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,7 +210,7 @@ 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: |
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
10
.github/workflows/reusable_publish_docker.yaml
vendored
10
.github/workflows/reusable_publish_docker.yaml
vendored
@@ -26,10 +26,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2 # TODO needs to be updated
|
||||
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,7 +39,7 @@ jobs:
|
||||
for img in /tmp/falco-images/falco-*.tar; do docker load --input $img; done
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2 # TODO needs to be updated
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USER }}
|
||||
password: ${{ secrets.DOCKERHUB_SECRET }}
|
||||
@@ -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,7 +76,7 @@ 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@0.3.1 # TODO needs to be updated (it might have cosign integration!)
|
||||
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 }}
|
||||
|
||||
20
.github/workflows/reusable_publish_packages.yaml
vendored
20
.github/workflows/reusable_publish_packages.yaml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
container: docker.io/centos:7
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
@@ -38,37 +38,37 @@ 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@v2 # TODO needs to be updated
|
||||
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
|
||||
@@ -112,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: |
|
||||
@@ -128,13 +128,13 @@ jobs:
|
||||
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
|
||||
|
||||
@@ -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@v3 # TODO needs to be updated
|
||||
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"
|
||||
|
||||
4
.github/workflows/staticanalysis.yaml
vendored
4
.github/workflows/staticanalysis.yaml
vendored
@@ -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
|
||||
|
||||
22
CHANGELOG.md
22
CHANGELOG.md
@@ -1,9 +1,29 @@
|
||||
# Change Log
|
||||
|
||||
## v0.36.2
|
||||
|
||||
Released on 2023-10-27
|
||||
|
||||
NO CHANGES IN FALCO, ALL CHANGES IN LIBS.
|
||||
|
||||
## v0.36.1
|
||||
|
||||
Released on 2023-10-16
|
||||
|
||||
### Major Changes
|
||||
|
||||
### Minor Changes
|
||||
|
||||
* feat(userspace): remove experimental outputs queue recovery strategies [[#2863](https://github.com/falcosecurity/falco/pull/2863)] - [@incertum](https://github.com/incertum)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix(userspace/falco): timer_delete() workaround due to bug in older GLIBC [[#2851](https://github.com/falcosecurity/falco/pull/2851)] - [@incertum](https://github.com/incertum)
|
||||
|
||||
|
||||
## v0.36.0
|
||||
|
||||
Released on 2023-09-26
|
||||
Released on 2023-09-25
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
|
||||
@@ -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 "00fa5c5196edf5858daf229ec8a96756d22fa854")
|
||||
set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=d7fd77830f97406828e7dd41bcd3178d54075c91638a8e40492d4e864457548a")
|
||||
set(FALCOSECURITY_LIBS_VERSION "0.13.4")
|
||||
set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=6b4a5c56422588b6ccaa53c976a9fbbcdb8d7918720c1b46207afe7ca46e8c29")
|
||||
endif()
|
||||
|
||||
# cd /path/to/build && cmake /path/to/source
|
||||
|
||||
47
falco.yaml
47
falco.yaml
@@ -273,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:
|
||||
@@ -303,24 +331,17 @@ rule_matching: first
|
||||
# If it does, it is most likely happening due to the entire event flow being too slow,
|
||||
# indicating that the server is under heavy load.
|
||||
#
|
||||
# Lowering the number of items can prevent memory from steadily increasing until the OOM
|
||||
# killer stops the Falco process. We provide recovery actions to self-limit or self-kill
|
||||
# in order to handle this situation earlier, similar to how we expose the kernel buffer size
|
||||
# as a parameter. However, it will not address the root cause of the event pipe not keeping up.
|
||||
#
|
||||
# `capacity`: the maximum number of items allowed in the queue is determined by this value.
|
||||
# Setting the value to 0 (which is the default) is equivalent to keeping the queue unbounded.
|
||||
# In other words, when this configuration is set to 0, the number of allowed items is effectively
|
||||
# set to the largest possible long value, disabling this setting.
|
||||
# In other words, when this configuration is set to 0, the number of allowed items is
|
||||
# effectively set to the largest possible long value, disabling this setting.
|
||||
#
|
||||
# `recovery`: strategy to follow when the queue becomes filled up. It applies only when the
|
||||
# queue is bounded and there is still available system memory. In the case of an unbounded
|
||||
# queue, if the available memory on the system is consumed, the Falco process would be
|
||||
# OOM killed. The value `exit` is the default, `continue` does nothing special and `empty`
|
||||
# empties the queue and then continues.
|
||||
# In the case of an unbounded queue, if the available memory on the system is consumed,
|
||||
# the Falco process would be OOM killed. When using this option and setting the capacity,
|
||||
# the current event would be dropped, and the event loop would continue. This behavior mirrors
|
||||
# kernel-side event drops when the buffer between kernel space and user space is full.
|
||||
outputs_queue:
|
||||
capacity: 0
|
||||
recovery: exit
|
||||
|
||||
|
||||
##########################
|
||||
|
||||
Submodule submodules/falcosecurity-rules updated: d119706074...77ba57ab2c
Submodule submodules/falcosecurity-testing updated: 92c313f5ca...62edc65a03
@@ -33,12 +33,6 @@ static std::vector<std::string> rule_matching_names = {
|
||||
"all"
|
||||
};
|
||||
|
||||
static std::vector<std::string> outputs_queue_recovery_names = {
|
||||
"continue",
|
||||
"exit",
|
||||
"empty",
|
||||
};
|
||||
|
||||
bool falco_common::parse_priority(std::string v, priority_type& out)
|
||||
{
|
||||
for (size_t i = 0; i < priority_names.size(); i++)
|
||||
@@ -66,19 +60,6 @@ falco_common::priority_type falco_common::parse_priority(std::string v)
|
||||
return out;
|
||||
}
|
||||
|
||||
bool falco_common::parse_queue_recovery(std::string v, outputs_queue_recovery_type& out)
|
||||
{
|
||||
for (size_t i = 0; i < outputs_queue_recovery_names.size(); i++)
|
||||
{
|
||||
if (!strcasecmp(v.c_str(), outputs_queue_recovery_names[i].c_str()))
|
||||
{
|
||||
out = (outputs_queue_recovery_type) i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool falco_common::format_priority(priority_type v, std::string& out, bool shortfmt)
|
||||
{
|
||||
if ((size_t) v < priority_names.size())
|
||||
|
||||
@@ -60,12 +60,6 @@ struct falco_exception : std::exception
|
||||
namespace falco_common
|
||||
{
|
||||
|
||||
enum outputs_queue_recovery_type {
|
||||
RECOVERY_CONTINUE = 0, /* outputs_queue_capacity recovery strategy of continuing on. */
|
||||
RECOVERY_EXIT = 1, /* outputs_queue_capacity recovery strategy of exiting, self OOM kill. */
|
||||
RECOVERY_EMPTY = 2, /* outputs_queue_capacity recovery strategy of emptying queue then continuing. */
|
||||
};
|
||||
|
||||
const std::string syscall_source = sinsp_syscall_event_source_name;
|
||||
|
||||
// Same as numbers/indices into the above vector
|
||||
@@ -83,7 +77,6 @@ namespace falco_common
|
||||
|
||||
bool parse_priority(std::string v, priority_type& out);
|
||||
priority_type parse_priority(std::string v);
|
||||
bool parse_queue_recovery(std::string v, outputs_queue_recovery_type& out);
|
||||
bool format_priority(priority_type v, std::string& out, bool shortfmt=false);
|
||||
std::string format_priority(priority_type v, bool shortfmt=false);
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ limitations under the License.
|
||||
#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";
|
||||
|
||||
@@ -75,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
|
||||
@@ -190,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, ...)
|
||||
rule_loader::compiler::compile_output out;
|
||||
rule_loader::compiler().compile(cfg, m_rule_collector, out);
|
||||
|
||||
// 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 : out.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())
|
||||
@@ -506,17 +469,7 @@ 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)
|
||||
{
|
||||
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
|
||||
void falco_engine::describe_rule(std::string *rule, bool json) const
|
||||
{
|
||||
if(!json)
|
||||
{
|
||||
@@ -545,20 +498,10 @@ void falco_engine::describe_rule(std::string *rule, const std::vector<std::share
|
||||
return;
|
||||
}
|
||||
|
||||
// use previously-loaded collector definitions to obtain a compiled
|
||||
// output of rules, macros, and lists.
|
||||
// note: we ignore the loading result (errors, warnings), as they should have
|
||||
// already been checked when previously-loading the rules files. Thus, we
|
||||
// assume that the definitions will give no compilation error.
|
||||
rule_loader::configuration cfg("", m_sources, "");
|
||||
cfg.output_extra = m_extra;
|
||||
cfg.replace_output_container_info = m_replace_container_info;
|
||||
rule_loader::compiler::compile_output compiled;
|
||||
rule_loader::compiler().compile(cfg, m_rule_collector, compiled);
|
||||
|
||||
// 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
|
||||
@@ -567,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;
|
||||
@@ -594,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 : compiled.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 : compiled.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 : compiled.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;
|
||||
@@ -637,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)
|
||||
@@ -713,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;
|
||||
@@ -1007,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
|
||||
|
||||
@@ -39,7 +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"
|
||||
|
||||
//
|
||||
// This class acts as the primary interface between a program and the
|
||||
@@ -57,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.
|
||||
@@ -135,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.
|
||||
@@ -313,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;
|
||||
|
||||
@@ -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 26
|
||||
#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 "df5b0b40d3e1dafc0de13459a4b889f8680ec154690f445952e74799920ae380"
|
||||
#define FALCO_ENGINE_CHECKSUM "98c6e665031b95c666a9ab02d5470e7008e8636bf02f4cc410912005b90dff5c"
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -19,23 +19,12 @@ 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)
|
||||
@@ -46,7 +35,6 @@ void filter_details_resolver::run(ast::expr* filter, filter_details& details)
|
||||
|
||||
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;
|
||||
@@ -57,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;
|
||||
@@ -83,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
/*!
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -86,6 +86,15 @@ falco::app::run_result falco::app::actions::open_live_inspector(
|
||||
falco_logger::log(LOG_INFO, "Opening '" + source + "' source with no driver\n");
|
||||
inspector->open_nodriver();
|
||||
}
|
||||
else if (s.options.userspace) /* udig engine. */
|
||||
{
|
||||
// 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_gvisor_enabled()) /* gvisor engine. */
|
||||
{
|
||||
falco_logger::log(LOG_INFO, "Opening '" + source + "' source with gVisor. Configuration path: " + s.options.gvisor_config);
|
||||
|
||||
@@ -65,7 +65,6 @@ falco::app::run_result falco::app::actions::init_outputs(falco::app::state& s)
|
||||
s.config->m_output_timeout,
|
||||
s.config->m_buffered_outputs,
|
||||
s.config->m_outputs_queue_capacity,
|
||||
s.config->m_outputs_queue_recovery,
|
||||
s.config->m_time_format_iso_8601,
|
||||
hostname));
|
||||
|
||||
|
||||
@@ -157,15 +157,13 @@ falco::app::run_result falco::app::actions::load_rules_files(falco::app::state&
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ options::options()
|
||||
list_plugins(false),
|
||||
list_syscall_events(false),
|
||||
markdown(false),
|
||||
userspace(false),
|
||||
modern_bpf(false),
|
||||
dry_run(false),
|
||||
nodriver(false)
|
||||
@@ -147,13 +148,14 @@ bool options::parse(int argc, char **argv, std::string &errstr)
|
||||
|
||||
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, -g (--gvisor-config), --modern-bpf, --nodriver, and the FALCO_BPF_PROBE env var");
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -218,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"))
|
||||
|
||||
@@ -75,6 +75,7 @@ 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;
|
||||
|
||||
@@ -36,11 +36,12 @@ 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),
|
||||
m_outputs_queue_capacity(DEFAULT_OUTPUTS_QUEUE_CAPACITY_UNBOUNDED_MAX_LONG_VALUE),
|
||||
m_outputs_queue_recovery(falco_common::RECOVERY_EXIT),
|
||||
m_time_format_iso_8601(false),
|
||||
m_output_timeout(2000),
|
||||
m_grpc_enabled(false),
|
||||
@@ -262,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))
|
||||
{
|
||||
@@ -281,11 +289,6 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h
|
||||
{
|
||||
m_outputs_queue_capacity = DEFAULT_OUTPUTS_QUEUE_CAPACITY_UNBOUNDED_MAX_LONG_VALUE;
|
||||
}
|
||||
std::string recovery = config.get_scalar<std::string>("outputs_queue.recovery", "exit");
|
||||
if (!falco_common::parse_queue_recovery(recovery, m_outputs_queue_recovery))
|
||||
{
|
||||
throw std::logic_error("Unknown recovery \"" + recovery + "\"--must be one of exit, continue, empty");
|
||||
}
|
||||
|
||||
m_time_format_iso_8601 = config.get_scalar<bool>("time_format_iso_8601", false);
|
||||
|
||||
|
||||
@@ -65,6 +65,8 @@ public:
|
||||
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;
|
||||
@@ -72,7 +74,6 @@ public:
|
||||
bool m_watch_config_files;
|
||||
bool m_buffered_outputs;
|
||||
size_t m_outputs_queue_capacity;
|
||||
falco_common::outputs_queue_recovery_type m_outputs_queue_recovery;
|
||||
bool m_time_format_iso_8601;
|
||||
uint32_t m_output_timeout;
|
||||
|
||||
|
||||
@@ -48,7 +48,6 @@ falco_outputs::falco_outputs(
|
||||
uint32_t timeout,
|
||||
bool buffered,
|
||||
size_t outputs_queue_capacity,
|
||||
falco_common::outputs_queue_recovery_type outputs_queue_recovery,
|
||||
bool time_format_iso_8601,
|
||||
const std::string& hostname)
|
||||
{
|
||||
@@ -67,7 +66,6 @@ falco_outputs::falco_outputs(
|
||||
add_output(output);
|
||||
}
|
||||
m_outputs_queue_num_drops = {0};
|
||||
m_outputs_queue_recovery = outputs_queue_recovery;
|
||||
#ifndef __EMSCRIPTEN__
|
||||
m_queue.set_capacity(outputs_queue_capacity);
|
||||
m_worker_thread = std::thread(&falco_outputs::worker, this);
|
||||
@@ -287,29 +285,11 @@ inline void falco_outputs::push(const ctrl_msg& cmsg)
|
||||
#ifndef __EMSCRIPTEN__
|
||||
if (!m_queue.try_push(cmsg))
|
||||
{
|
||||
switch (m_outputs_queue_recovery)
|
||||
if(m_outputs_queue_num_drops.load() == 0)
|
||||
{
|
||||
case falco_common::RECOVERY_EXIT:
|
||||
throw falco_exception("Fatal error: Output queue out of memory. Exiting ...");
|
||||
case falco_common::RECOVERY_EMPTY:
|
||||
/* Print a log just the first time */
|
||||
if(m_outputs_queue_num_drops.load() == 0)
|
||||
{
|
||||
falco_logger::log(LOG_ERR, "Output queue out of memory. Drop event plus events in queue due to emptying the queue; continue on ...");
|
||||
}
|
||||
m_outputs_queue_num_drops += m_queue.size() + 1;
|
||||
m_queue.clear();
|
||||
break;
|
||||
case falco_common::RECOVERY_CONTINUE:
|
||||
if(m_outputs_queue_num_drops.load() == 0)
|
||||
{
|
||||
falco_logger::log(LOG_ERR, "Output queue out of memory. Drop event and continue on ...");
|
||||
}
|
||||
m_outputs_queue_num_drops++;
|
||||
break;
|
||||
default:
|
||||
throw falco_exception("Fatal error: strategy unknown. Exiting ...");
|
||||
falco_logger::log(LOG_ERR, "Outputs queue out of memory. Drop event and continue on ...");
|
||||
}
|
||||
m_outputs_queue_num_drops++;
|
||||
}
|
||||
#else
|
||||
for (auto o : m_outputs)
|
||||
|
||||
@@ -50,7 +50,6 @@ public:
|
||||
uint32_t timeout,
|
||||
bool buffered,
|
||||
size_t outputs_queue_capacity,
|
||||
falco_common::outputs_queue_recovery_type outputs_queue_recovery,
|
||||
bool time_format_iso_8601,
|
||||
const std::string& hostname);
|
||||
|
||||
@@ -87,8 +86,8 @@ public:
|
||||
void reopen_outputs();
|
||||
|
||||
/*!
|
||||
\brief Return the number of currently dropped events as a result of failed push attempts
|
||||
into the outputs queue when using `continue` or `empty` recovery strategies.
|
||||
\brief Return the number of events currently dropped due to failed push
|
||||
attempts into the outputs queue
|
||||
*/
|
||||
uint64_t get_outputs_queue_num_drops();
|
||||
|
||||
@@ -121,7 +120,6 @@ private:
|
||||
falco_outputs_cbq m_queue;
|
||||
#endif
|
||||
|
||||
falco_common::outputs_queue_recovery_type m_outputs_queue_recovery;
|
||||
std::atomic<uint64_t> m_outputs_queue_num_drops;
|
||||
std::thread m_worker_thread;
|
||||
inline void push(const ctrl_msg& cmsg);
|
||||
|
||||
@@ -16,7 +16,6 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
#include "config_falco.h"
|
||||
#include "falco_engine.h"
|
||||
#include "falco_engine_version.h"
|
||||
#include "grpc_server_impl.h"
|
||||
#include "grpc_queue.h"
|
||||
@@ -80,10 +79,6 @@ void falco::grpc::server_impl::version(const context& ctx, const version::reques
|
||||
|
||||
res.set_engine_version(FALCO_ENGINE_VERSION);
|
||||
res.set_engine_fields_checksum(FALCO_ENGINE_CHECKSUM);
|
||||
auto engine_version = falco_engine::engine_version();
|
||||
res.set_engine_major(engine_version.major());
|
||||
res.set_engine_minor(engine_version.minor());
|
||||
res.set_engine_patch(engine_version.patch());
|
||||
|
||||
res.set_major(FALCO_VERSION_MAJOR);
|
||||
res.set_minor(FALCO_VERSION_MINOR);
|
||||
|
||||
@@ -34,6 +34,12 @@ limitations under the License.
|
||||
// check that this value changed since their last observation.
|
||||
static std::atomic<stats_writer::ticker_t> s_timer((stats_writer::ticker_t) 0);
|
||||
static timer_t s_timerid;
|
||||
// note: 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).
|
||||
// Just performing a nullptr check is not enough as even after creating the timer, s_timerid
|
||||
// remains a nullptr somehow.
|
||||
bool s_timerid_exists = false;
|
||||
|
||||
static void timer_handler(int signum)
|
||||
{
|
||||
@@ -60,25 +66,31 @@ bool stats_writer::init_ticker(uint32_t interval_msec, std::string &err)
|
||||
sev.sigev_value.sival_ptr = &s_timerid;
|
||||
#ifndef __EMSCRIPTEN__
|
||||
// delete any previously set timer
|
||||
if (s_timerid)
|
||||
if (s_timerid_exists)
|
||||
{
|
||||
if (timer_delete(s_timerid) == -1)
|
||||
if (timer_delete(s_timerid) == -1)
|
||||
{
|
||||
err = std::string("Failed to delete existing timer: ") + strerror(errno);
|
||||
err = std::string("Could not delete previous timer: ") + strerror(errno);
|
||||
return false;
|
||||
}
|
||||
s_timerid_exists = false;
|
||||
}
|
||||
if (timer_create(CLOCK_MONOTONIC, &sev, &s_timerid) == -1) {
|
||||
|
||||
if (timer_create(CLOCK_MONOTONIC, &sev, &s_timerid) == -1)
|
||||
{
|
||||
err = std::string("Could not create periodic timer: ") + strerror(errno);
|
||||
return false;
|
||||
}
|
||||
s_timerid_exists = true;
|
||||
|
||||
#endif
|
||||
timer.it_value.tv_sec = interval_msec / 1000;
|
||||
timer.it_value.tv_nsec = (interval_msec % 1000) * 1000 * 1000;
|
||||
timer.it_interval = timer.it_value;
|
||||
|
||||
#ifndef __EMSCRIPTEN__
|
||||
if (timer_settime(s_timerid, 0, &timer, NULL) == -1) {
|
||||
if (timer_settime(s_timerid, 0, &timer, NULL) == -1)
|
||||
{
|
||||
err = std::string("Could not set up periodic timer: ") + strerror(errno);
|
||||
return false;
|
||||
}
|
||||
@@ -120,8 +132,7 @@ stats_writer::stats_writer(
|
||||
if (m_initialized)
|
||||
{
|
||||
#ifndef __EMSCRIPTEN__
|
||||
// capacity and controls should not be relevant for stats outputs, adopt capacity
|
||||
// for completeness, but do not implement config recovery strategies.
|
||||
// Adopt capacity for completeness, even if it's likely not relevant
|
||||
m_queue.set_capacity(config->m_outputs_queue_capacity);
|
||||
m_worker = std::thread(&stats_writer::worker, this);
|
||||
#endif
|
||||
@@ -141,10 +152,10 @@ stats_writer::~stats_writer()
|
||||
}
|
||||
// delete timerID and reset timer
|
||||
#ifndef __EMSCRIPTEN__
|
||||
if (s_timerid)
|
||||
if (s_timerid_exists)
|
||||
{
|
||||
timer_delete(s_timerid);
|
||||
s_timerid = nullptr;
|
||||
s_timerid_exists = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -240,7 +251,7 @@ void stats_writer::collector::get_metrics_output_fields_wrapper(
|
||||
{
|
||||
static const char* all_driver_engines[] = {
|
||||
BPF_ENGINE, KMOD_ENGINE, MODERN_BPF_ENGINE,
|
||||
SOURCE_PLUGIN_ENGINE, NODRIVER_ENGINE, GVISOR_ENGINE };
|
||||
SOURCE_PLUGIN_ENGINE, NODRIVER_ENGINE, UDIG_ENGINE, GVISOR_ENGINE };
|
||||
const scap_agent_info* agent_info = inspector->get_agent_info();
|
||||
const scap_machine_info* machine_info = inspector->get_machine_info();
|
||||
|
||||
|
||||
@@ -45,9 +45,6 @@ message response
|
||||
string prerelease = 5;
|
||||
string build = 6;
|
||||
// falco engine version
|
||||
uint32 engine_minor = 7;
|
||||
uint32 engine_version = 7;
|
||||
string engine_fields_checksum = 8;
|
||||
uint32 engine_major = 9;
|
||||
uint32 engine_patch = 10;
|
||||
string engine_version = 11;
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ static inline std::string get_driver_schema_version(const std::shared_ptr<sinsp>
|
||||
falco::versions_info::versions_info(const std::shared_ptr<sinsp>& inspector)
|
||||
{
|
||||
falco_version = FALCO_VERSION;
|
||||
engine_version = FALCO_ENGINE_VERSION;
|
||||
engine_version = std::to_string(FALCO_ENGINE_VERSION);
|
||||
libs_version = FALCOSECURITY_LIBS_VERSION;
|
||||
plugin_api_version = inspector->get_plugin_api_version();
|
||||
driver_api_version = get_driver_api_version(inspector);
|
||||
|
||||
Reference in New Issue
Block a user