Compare commits

..

11 Commits

Author SHA1 Message Date
Andrea Terzolo
76726d7def chore: bump libs version
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-11-29 11:40:11 +01:00
Andrea Terzolo
da5f0a8d4f update: add HOST_ROOT env in dockerfile
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-11-15 16:09:39 +01:00
Andrea Terzolo
5d1b0c5717 chore: bump libs version
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-11-14 12:38:36 +01:00
Federico Di Pierro
d8d6c0ec30 new(scrips): improve systemd units for rpm and debian.
Unify them; plus, rework systemd units to support eBPF too.

Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-11-11 15:42:21 +00:00
Andrea Terzolo
0202996587 chore: bump libs
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-11-08 00:02:21 +01:00
Andrea Terzolo
b4e5adc585 fix(CI): updating the source and build paths
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-11-07 17:48:16 +01:00
Andrea Terzolo
84effdcf2d update: add parallel build
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-11-06 20:25:53 +01:00
Andrea Terzolo
c22b3b5195 REMOVE: introduce new GH job to build modern BPF packages
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-11-06 16:10:19 +01:00
Andrea Terzolo
aa715b20f8 REMOVE: add a local dockerfile to push temp docker images for modern BPF
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-11-06 16:10:19 +01:00
Andrea Terzolo
cad172cbe5 ci: introduce new CircleCI jobs to build modern BPF
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-11-06 16:10:18 +01:00
Andrea Terzolo
2db6c033cc chore: bump libs version
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-11-06 14:57:17 +01:00
54 changed files with 638 additions and 716 deletions

View File

@@ -3,46 +3,48 @@ jobs:
"build-arm64": "build-arm64":
machine: machine:
enabled: true enabled: true
image: ubuntu-2004:202101-01 image: ubuntu-2204:2022.10.2
resource_class: arm.medium resource_class: arm.medium
steps: steps:
# Install dependencies to build the modern BPF probe skeleton.
- run:
name: Install deps ⛓️
command: |
sudo apt update
sudo apt install -y --no-install-recommends ca-certificates cmake build-essential clang-14 git pkg-config autoconf automake libelf-dev
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-14 90
sudo update-alternatives --install /usr/bin/llvm-strip llvm-strip /usr/bin/llvm-strip-14 90
git clone https://github.com/libbpf/bpftool.git --branch v7.0.0 --single-branch
cd bpftool
git submodule update --init
cd src && sudo make install
# Path to the source code
- checkout: - checkout:
path: /tmp/source-arm64/falco path: /tmp/source-arm64/falco
# Build the skeleton
- run: - run:
name: Prepare project name: Build modern BPF skeleton 🐝
command: | command: |
mkdir -p /tmp/build-arm64 && mkdir -p /tmp/build-arm64/release && \ mkdir -p /tmp/source-arm64/falco/skeleton-build
docker run -e BUILD_TYPE="release" -it -v /tmp/source-arm64:/source -v /tmp/build-arm64:/build \ cd /tmp/source-arm64/falco/skeleton-build && cmake -DUSE_BUNDLED_DEPS=ON -DBUILD_FALCO_MODERN_BPF=ON -DCREATE_TEST_TARGETS=Off ../
falcosecurity/falco-builder:latest \ make ProbeSkeleton
cmake
# Build the Falco packages (tar, deb, rpm) inside the centos7 builder.
# This dockerfile returns as output:
# - the build directory. (under /tmp/${DEST_BUILD_DIR})
# - the 3 packages: tar, deb, rpm. (under /tmp/packages)
- run: - run:
name: Build name: Build Falco packages 🏗️
command: | command: |
docker run -e BUILD_TYPE="release" -it -v /tmp/source-arm64:/source -v /tmp/build-arm64:/build \ DOCKER_BUILDKIT=1 docker build -f /tmp/source-arm64/falco/docker/builder/centos7-builder.Dockerfile --output type=local,dest=/tmp --build-arg CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release -DUSE_BUNDLED_DEPS=On -DFALCO_ETC_DIR=/etc/falco -DBUILD_FALCO_MODERN_BPF=ON -DMODERN_BPF_SKEL_DIR=/source/skeleton-build/skel_dir -DBUILD_DRIVER=Off -DBUILD_BPF=Off" --build-arg DEST_BUILD_DIR=/build-arm64/release /tmp/source-arm64/falco
falcosecurity/falco-builder:latest \
all
- run:
name: Run unit tests
command: |
docker run -e BUILD_TYPE="release" -it -v /tmp/source-arm64:/source -v /tmp/build-arm64:/build \
falcosecurity/falco-builder:latest \
tests
- run:
name: Build packages
command: |
docker run -e BUILD_TYPE="release" -it -v /tmp/source-arm64:/source -v /tmp/build-arm64:/build \
falcosecurity/falco-builder:latest \
package
- run:
name: Prepare Artifacts
command: |
mkdir -p /tmp/packages
cp /tmp/build-arm64/release/*.deb /tmp/packages
cp /tmp/build-arm64/release/*.tar.gz /tmp/packages
cp /tmp/build-arm64/release/*.rpm /tmp/packages
- store_artifacts: - store_artifacts:
path: /tmp/packages path: /tmp/packages
destination: /packages destination: /packages
- persist_to_workspace: - persist_to_workspace:
root: /tmp root: /tmp
paths: paths:
@@ -67,7 +69,7 @@ jobs:
command: | command: |
mkdir -p /build-static/release mkdir -p /build-static/release
cd /build-static/release cd /build-static/release
cmake -DCPACK_GENERATOR=TGZ -DBUILD_BPF=Off -DBUILD_DRIVER=Off -DCMAKE_BUILD_TYPE=Release -DUSE_BUNDLED_DEPS=On -DUSE_BUNDLED_LIBELF=Off -DMUSL_OPTIMIZED_BUILD=On -DFALCO_ETC_DIR=/etc/falco /source-static/falco cmake -DCPACK_GENERATOR=TGZ -DBUILD_BPF=Off -DBUILD_DRIVER=Off -DCMAKE_BUILD_TYPE=Release -DUSE_BUNDLED_LIBELF=Off -DUSE_BUNDLED_DEPS=On -DMUSL_OPTIMIZED_BUILD=On -DFALCO_ETC_DIR=/etc/falco /source-static/falco
- run: - run:
name: Build name: Build
command: | command: |
@@ -96,43 +98,56 @@ jobs:
paths: paths:
- build-static/release - build-static/release
- source-static - source-static
# Build using our own builder base image using centos 7
# This build is static, dependencies are bundled in the Falco binary # This build is static, dependencies are bundled in the Falco binary
"build-centos7": "build-centos7":
docker: machine:
- image: falcosecurity/falco-builder:latest enabled: true
environment: image: ubuntu-2204:2022.10.2
BUILD_TYPE: "release"
steps: steps:
- checkout:
path: /source/falco # Install dependencies to build the modern BPF probe skeleton.
- run: - run:
name: Prepare project name: Install deps ⛓️
command: /usr/bin/entrypoint cmake
- run:
name: Build
command: /usr/bin/entrypoint all
- run:
name: Run unit tests
command: /usr/bin/entrypoint tests
- run:
name: Build packages
command: /usr/bin/entrypoint package
- persist_to_workspace:
root: /
paths:
- build/release
- source
- run:
name: Prepare artifacts
command: | command: |
mkdir -p /tmp/packages sudo apt update
cp /build/release/*.deb /tmp/packages sudo apt install -y --no-install-recommends ca-certificates cmake build-essential clang-14 git pkg-config autoconf automake libelf-dev
cp /build/release/*.tar.gz /tmp/packages sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-14 90
cp /build/release/*.rpm /tmp/packages sudo update-alternatives --install /usr/bin/llvm-strip llvm-strip /usr/bin/llvm-strip-14 90
git clone https://github.com/libbpf/bpftool.git --branch v7.0.0 --single-branch
cd bpftool
git submodule update --init
cd src && sudo make install
# Path for the source code
- checkout:
path: /tmp/source/falco
- run:
name: Build modern BPF skeleton 🐝
command: |
mkdir -p /tmp/source/falco/skeleton-build
cd /tmp/source/falco/skeleton-build && cmake -DUSE_BUNDLED_DEPS=ON -DBUILD_FALCO_MODERN_BPF=ON -DCREATE_TEST_TARGETS=Off ../
make ProbeSkeleton
# Build the Falco packages (tar, deb, rpm) inside the centos7 builder.
# This dockerfile returns as output:
# - the build directory. (under /tmp/${DEST_BUILD_DIR})
# - the 3 packages: tar, deb, rpm. (under /tmp/packages)
- run:
name: Build Falco packages 🏗️
command: |
DOCKER_BUILDKIT=1 docker build -f /tmp/source/falco/docker/builder/centos7-builder.Dockerfile --output type=local,dest=/tmp --build-arg CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release -DUSE_BUNDLED_DEPS=On -DFALCO_ETC_DIR=/etc/falco -DBUILD_FALCO_MODERN_BPF=ON -DMODERN_BPF_SKEL_DIR=/source/skeleton-build/skel_dir -DBUILD_DRIVER=Off -DBUILD_BPF=Off" --build-arg DEST_BUILD_DIR=/build/release /tmp/source/falco
- store_artifacts: - store_artifacts:
path: /tmp/packages path: /tmp/packages
destination: /packages destination: /packages
- persist_to_workspace:
root: /tmp
paths:
- build/release
- source
# Execute integration tests based on the build results coming from the "build-centos7" job # Execute integration tests based on the build results coming from the "build-centos7" job
"tests-integration": "tests-integration":
docker: docker:
@@ -147,9 +162,12 @@ jobs:
at: / at: /
- run: - run:
name: Execute integration tests name: Execute integration tests
command: /usr/bin/entrypoint test command: |
/usr/bin/entrypoint test
- store_test_results: - store_test_results:
path: /build/release/integration-tests-xunit path: /build/release/integration-tests-xunit
# Execute integration tests based on the build results coming from the "build-musl" job
"tests-integration-static": "tests-integration-static":
docker: docker:
- image: falcosecurity/falco-tester:latest - image: falcosecurity/falco-tester:latest

View File

@@ -14,7 +14,6 @@ jobs:
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
- name: Update base image - name: Update base image
run: sudo apt update -y run: sudo apt update -y
@@ -48,7 +47,6 @@ jobs:
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
- name: Update base image - name: Update base image
run: sudo apt update -y run: sudo apt update -y
@@ -82,7 +80,6 @@ jobs:
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
- name: Update base image - name: Update base image
run: sudo apt update -y run: sudo apt update -y
@@ -116,7 +113,6 @@ jobs:
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
- name: Update base image - name: Update base image
run: sudo apt update -y run: sudo apt update -y
@@ -155,7 +151,6 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
path: falco path: falco
ref: ${{ github.event.pull_request.head.sha }}
- name: Link falco repo to /source/falco - name: Link falco repo to /source/falco
run: | run: |
@@ -172,4 +167,48 @@ jobs:
run: /usr/bin/entrypoint tests run: /usr/bin/entrypoint tests
- name: Build packages - name: Build packages
run: /usr/bin/entrypoint package run: /usr/bin/entrypoint package
# Before merging the PR we must remove this, right now we keep it just to have packages also from there
build-modern-bpf-packages:
runs-on: ubuntu-22.04
steps:
- name: Install deps ⛓️
run: |
sudo apt update
sudo apt install -y --no-install-recommends ca-certificates cmake build-essential clang-14 git pkg-config autoconf automake libtool libelf-dev
- name: Checkout Falco 🦅
uses: actions/checkout@v3
with:
fetch-depth: 0
# Build the modern BPF skeleton
- name: Build modern BPF skeleton 🐝
run: |
mkdir -p skeleton-build
cd skeleton-build && cmake -DUSE_BUNDLED_DEPS=ON -DBUILD_FALCO_MODERN_BPF=ON -DCREATE_TEST_TARGETS=Off ../
make ProbeSkeleton
- name: Build the artifact from the docker image 🏗️
run: |
DOCKER_BUILDKIT=1 docker build -f ./docker/builder/centos7-builder.Dockerfile --output type=local,dest=export-artifacts --build-arg CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release -DUSE_BUNDLED_DEPS=On -DFALCO_ETC_DIR=/etc/falco -DBUILD_FALCO_MODERN_BPF=ON -DMODERN_BPF_SKEL_DIR=/source/skeleton-build/skel_dir -DBUILD_DRIVER=Off -DBUILD_BPF=Off" .
- name: Upload deb ⏫
uses: actions/upload-artifact@v3
with:
name: falco.deb
path: ./export-artifacts/packages/falco-*.deb
- name: Upload rpm ⏫
uses: actions/upload-artifact@v3
with:
name: falco.rpm
path: ./export-artifacts/packages/falco-*.rpm
- name: Upload tar.gz ⏫
uses: actions/upload-artifact@v3
with:
name: falco.tar.gz
path: ./export-artifacts/packages/falco-*.tar.gz

View File

@@ -39,7 +39,7 @@ This is a list of production adopters of Falco (in alphabetical order):
* [Logz.io](https://logz.io/) - Logz.io is a cloud observability platform for modern engineering teams. The Logz.io platform consists of three products — Log Management, Infrastructure Monitoring, and Cloud SIEM — that work together to unify the jobs of monitoring, troubleshooting, and security. We empower engineers to deliver better software by offering the world's most popular open source observability tools — the ELK Stack, Grafana, and Jaeger — in a single, easy to use, and powerful platform purpose-built for monitoring distributed cloud environments. Cloud SIEM supports data from multiple sources, including Falco's alerts, and offers useful rules and dashboards content to visualize and manage incidents across your systems in a unified UI. * [Logz.io](https://logz.io/) - Logz.io is a cloud observability platform for modern engineering teams. The Logz.io platform consists of three products — Log Management, Infrastructure Monitoring, and Cloud SIEM — that work together to unify the jobs of monitoring, troubleshooting, and security. We empower engineers to deliver better software by offering the world's most popular open source observability tools — the ELK Stack, Grafana, and Jaeger — in a single, easy to use, and powerful platform purpose-built for monitoring distributed cloud environments. Cloud SIEM supports data from multiple sources, including Falco's alerts, and offers useful rules and dashboards content to visualize and manage incidents across your systems in a unified UI.
* https://logz.io/blog/k8s-security-with-falco-and-cloud-siem/ * https://logz.io/blog/k8s-security-with-falco-and-cloud-siem/
* [MathWorks](https://mathworks.com) - MathWorks develops mathematical computing software for engineers and scientists. MathWorks uses Falco for Kubernetes threat detection, unexpected application behavior, and maps Falco rules to their cloud infrastructure's security kill chain model. MathWorks presented their Falco use case at [KubeCon + CloudNativeCon North America 2020](https://www.youtube.com/watch?v=L-5RYBTV010). * [MathWorks](https://mathworks.com) - MathWorks develops mathematical computing software for engineers and scientists. MathWorks uses Falco for Kubernetes threat detection, unexpected application behavior, and maps Falco rules to their cloud infrastructure's security kill chain model. MathWorks presented their Falco use case at [KubeCon + CloudNativeCon North America 2020](https://www.youtube.com/watch?v=L-5RYBTV010).
* [Pocteo](https://pocteo.co) - Pocteo helps with Kubernetes adoption in enterprises by providing a variety of services such as training, consulting, auditing and mentoring. We build CI/CD pipelines the GitOps way, as well as design and run k8s clusters. Pocteo uses Falco as a runtime monitoring system to secure clients' workloads against suspicious behavior and ensure k8s pods immutability. We also use Falco to collect, process and act on security events through a response engine and serverless functions. * [Pocteo](https://pocteo.co) - Pocteo helps with Kubernetes adoption in enterprises by providing a variety of services such as training, consulting, auditing and mentoring. We build CI/CD pipelines the GitOps way, as well as design and run k8s clusters. Pocteo uses Falco as a runtime monitoring system to secure clients' workloads against suspicious behavior and ensure k8s pods immutability. We also use Falco to collect, process and act on security events through a response engine and serverless functions.
@@ -70,8 +70,6 @@ This is a list of production adopters of Falco (in alphabetical order):
* [Sysdig](https://www.sysdig.com/) Sysdig originally created Falco in 2016 to detect unexpected or suspicious activity using a rules engine on top of the data that comes from the sysdig kernel system call driver. Sysdig provides tooling to help with vulnerability management, compliance, detection, incident response and forensics in Cloud-native environments. Sysdig Secure has extended Falco to include: a rule library, the ability to update macros, lists & rules via the user interface and API, automated tuning of rules, and rule creation based on profiling known system behavior. On top of the basic Falco rules, Sysdig Secure implements the concept of a "Security policy" that can comprise several rules which are evaluated for a user-defined infrastructure scope like Kubernetes namespaces, OpenShift clusters, deployment workload, cloud regions etc. * [Sysdig](https://www.sysdig.com/) Sysdig originally created Falco in 2016 to detect unexpected or suspicious activity using a rules engine on top of the data that comes from the sysdig kernel system call driver. Sysdig provides tooling to help with vulnerability management, compliance, detection, incident response and forensics in Cloud-native environments. Sysdig Secure has extended Falco to include: a rule library, the ability to update macros, lists & rules via the user interface and API, automated tuning of rules, and rule creation based on profiling known system behavior. On top of the basic Falco rules, Sysdig Secure implements the concept of a "Security policy" that can comprise several rules which are evaluated for a user-defined infrastructure scope like Kubernetes namespaces, OpenShift clusters, deployment workload, cloud regions etc.
* [Xenit AB](https://xenit.se/contact/) Xenit is a growth company with services within cloud and digital transformation. We provide an open-source Kubernetes framework that we leverage to help our customers get their applications to production as quickly and as securely as possible. We use Falco's detection capabilities to identify anomalous behaviour within our clusters in both Azure and AWS.
## Projects that use Falco libs ## Projects that use Falco libs
* [R6/Phoenix](https://r6security.com/) is an attack surface protection company that uses moving target defense to provide fully automated, proactive and devops friendly security to its customers. There are a set of policies you can add to enable the moving target defense capabilities. Some of them are triggered by a combination of Falco's findings. You can kill, restart and rename pods according to the ever changing policies. * [R6/Phoenix](https://r6security.com/) is an attack surface protection company that uses moving target defense to provide fully automated, proactive and devops friendly security to its customers. There are a set of policies you can add to enable the moving target defense capabilities. Some of them are triggered by a combination of Falco's findings. You can kill, restart and rename pods according to the ever changing policies.

View File

@@ -1,14 +1,5 @@
# Change Log # Change Log
## v0.33.1
Released on 2022-11-24
### Minor Changes
* update(falco): fix container-gvisor and kubernetes-gvisor print options [[#2288](https://github.com/falcosecurity/falco/pull/2288)]
* Update libs to 0.9.2, fixing potential CLBO on gVisor+Kubernetes and crash with eBPF when some CPUs are offline [[#2299](https://github.com/falcosecurity/falco/pull/2299)] - [@LucaGuerra](https://github.com/LucaGuerra)
## v0.33.0 ## v0.33.0
Released on 2022-10-19 Released on 2022-10-19

View File

@@ -181,6 +181,9 @@ include(cxxopts)
# One TBB # One TBB
include(tbb) include(tbb)
#string-view-lite
include(DownloadStringViewLite)
if(NOT MINIMAL_BUILD) if(NOT MINIMAL_BUILD)
include(zlib) include(zlib)
include(cares) include(cares)

View File

@@ -1,77 +1,18 @@
# Falco Release Process # Falco Release Process
Our release process is mostly automated, but we still need some manual steps to initiate and complete it.
## Overview
This document provides the process to create a new Falco release. In addition, it provides information about the versioning of the Falco components. At a high level each Falco release consists of the following main components:
- Falco binary (userspace)
- Falco kernel driver object files (kernel space)
- Option 1: Kernel module (`.ko` files)
- Option 2: eBPF (`.o` files)
- Falco config and primary rules `.yaml` files (userspace)
- Falco plugins (userspace - optional)
One nice trait about releasing separate artifacts for userspace and kernel space is that Falco is amenable to supporting a large array of environments, that is, multiple kernel versions, distros and architectures (see `libs` [driver - kernel version support matrix](https://github.com/falcosecurity/libs#drivers-officially-supported-architectures)). The Falco project manages the release of both the Falco userspace binary and pre-compiled Falco kernel drivers for the most popular kernel versions and distros. The build and publish process is managed by the [test-infra](https://github.com/falcosecurity/test-infra) repo. The Falco userspace executable includes bundled dependencies, so that it can be run from anywhere.
The Falco project also publishes all sources for each component. In fact, sources are included in the Falco release in the same way as some plugins (k8saudit and cloudtrail) as well as the rules that are shipped together with Falco. This empowers the end user to audit the integrity of the project as well as build kernel drivers for custom kernels or not officially supported kernels / distros (see [driverkit](https://github.com/falcosecurity/driverkit) for more information). While the Falco project is deeply embedded into an ecosystem of supporting [Falco sub-projects](https://github.com/falcosecurity/evolution) that aim to make the deployment of Falco easy, user-friendly, extendible and cloud-native, core Falco is split across two repos, [falco](https://github.com/falcosecurity/falco) (this repo) and [libs](https://github.com/falcosecurity/libs). The `libs` repo contains >90% of Falco's core features and is the home of each of the kernel drivers and engines. More details are provided in the [Falco Components Versioning](#falco-components-versioning) section.
Finally, the release process follows a transparent process described in more detail in the following sections and the official [Falco docs](https://falco.org/) contain rich information around building, installing and using Falco.
### Falco Binaries, Rules and Sources Artifacts - Quick Links
The Falco project publishes all sources and the Falco userspace binaries as GitHub releases. Rules are also released in the GitHub tree Falco release tag.
- [Falco Releases](https://github.com/falcosecurity/falco/releases)
- `tgz`, `rpm` and `deb` Falco binary packages (contains sources, including driver sources, Falco rules as well as k8saudit and cloudtrail plugins)
- `tgz`, `zip` source code
- [Libs Releases](https://github.com/falcosecurity/libs/releases)
- `tgz`, `zip` source code
- Falco Rules (GitHub tree approach)
- RELEASE="x.y.z", `https://github.com/falcosecurity/falco/tree/${RELEASE}/rules`
Alternatively Falco binaries or plugins can be downloaded from the Falco Artifacts repo.
- [Falco Artifacts Repo Packages Root](https://download.falco.org/?prefix=packages/)
- [Falco Artifacts Repo Plugins Root](https://download.falco.org/?prefix=plugins/)
### Falco Drivers Artifacts Repo - Quick Links
The Falco project publishes all drivers for each release for all popular kernel versions / distros and `x86_64` and `aarch64` architectures to the Falco project managed Artifacts repo. The Artifacts repo follows standard directory level conventions. The respective driver object file is prefixed by distro and named / versioned by kernel release - `$(uname -r)`. Pre-compiled drivers are released with a [best effort](https://github.com/falcosecurity/falco/blob/master/proposals/20200818-artifacts-storage.md#notice) notice. This is because gcc (`kmod`) and clang (`bpf`) compilers or for example the eBPF verifier are not perfect. More details around driver versioning and driver compatibility are provided in the [Falco Components Versioning](#falco-components-versioning) section. Short preview: If you use the standard Falco setup leveraging driver-loader, [driver-loader script](https://github.com/falcosecurity/falco/blob/master/scripts/falco-driver-loader) will fetch the kernel space artifact (object file) corresponding to the default `DRIVER_VERSION` Falco was shipped with.
- [Falco Artifacts Repo Drivers Root](https://download.falco.org/?prefix=driver/)
- Option 1: Kernel module (`.ko` files) - all under same driver version directory
- Option 2: eBPF (`.o` files) - all under same driver version directory
### Timeline
Falco releases are due to happen 3 times per year. Our current schedule sees a new release by the end of January, May, and September each year. Hotfix releases can happen whenever it's needed.
Changes and new features are grouped in [milestones](https://github.com/falcosecurity/falco/milestones), the milestone with the next version represents what is going to be released. Changes and new features are grouped in [milestones](https://github.com/falcosecurity/falco/milestones), the milestone with the next version represents what is going to be released.
Falco releases are due to happen 3 times per year. Our current schedule sees a new release by the end of January, May, and September each year. Hotfix releases can happen whenever it's needed.
### Procedures
The release process is mostly automated requiring only a few manual steps to initiate and complete it.
Moreover, we need to assign owners for each release (usually we pair a new person with an experienced one). Assignees and the due date are proposed during the [weekly community call](https://github.com/falcosecurity/community). Moreover, we need to assign owners for each release (usually we pair a new person with an experienced one). Assignees and the due date are proposed during the [weekly community call](https://github.com/falcosecurity/community).
At a high level each Falco release needs to follow a pre-determined sequencing of releases and build order:
- [1 - 3] `libs` (+ `driver`) and `plugins` components releases
- [4] Falco driver pre-compiled object files push to Falco's Artifacts repo
- [5] Falco userspace binary + rules release
Finally, on the proposed due date the assignees for the upcoming release proceed with the processes described below. Finally, on the proposed due date the assignees for the upcoming release proceed with the processes described below.
## Pre-Release Checklist ## Pre-Release Checklist
Prior to cutting a release the following preparatory steps should take 5 minutes using the GitHub UI. Before cutting a release we need to do some homework in the Falco repository. This should take 5 minutes using the GitHub UI.
### 1. Release notes ### 1. Release notes
- Find the previous release date (`YYYY-MM-DD`) by looking at the [Falco releases](https://github.com/falcosecurity/falco/releases) - Find the previous release date (`YYYY-MM-DD`) by looking at the [Falco releases](https://github.com/falcosecurity/falco/releases)
@@ -180,39 +121,3 @@ Announce the new release to the world!
- Send an announcement to cncf-falco-dev@lists.cncf.io (plain text, please) - Send an announcement to cncf-falco-dev@lists.cncf.io (plain text, please)
- Let folks in the slack #falco channel know about a new release came out - Let folks in the slack #falco channel know about a new release came out
- IFF the on going release introduces a **new minor version**, [archive a snapshot of the Falco website](https://github.com/falcosecurity/falco-website/blob/master/release.md#documentation-versioning) - IFF the on going release introduces a **new minor version**, [archive a snapshot of the Falco website](https://github.com/falcosecurity/falco-website/blob/master/release.md#documentation-versioning)
## Falco Components Versioning
This section provides more details around the versioning of all components that make up core Falco. It can also be a useful guide for the uninitiated to be more informed about Falco's source. Because the `libs` repo contains >90% of Falco's core features and is the home of each of the kernel drivers and engines, the [libs release doc](https://github.com/falcosecurity/libs/blob/master/release.md) is an excellent additional resource. In addition, the [plugins release doc](https://github.com/falcosecurity/plugins/blob/master/release.md) provides similar details around Falco's plugins. `SHA256` checksums are provided throughout Falco's source code to empower the end user to perform integrity checks. All Falco releases also contain the sources as part of the packages.
### Falco repo (this repo)
- Falco version is a git tag (`x.y.z`), see [Procedures](#procedures) section. Note that the Falco version is a sem-ver-like schema, but not fully compatible with sem-ver.
- [FALCO_ENGINE_VERSION](https://github.com/falcosecurity/falco/blob/master/userspace/engine/falco_engine_version.h) is not sem-ver and must be bumped either when a backward incompatible change has been introduced to the rules files syntax or `falco --list -N | sha256sum` has changed. Breaking changes introduced in the Falco engine are not necessarily tied to the drivers or libs versions. The primary idea behind the hash is that when new filter / display fields (see currently supported [Falco fields](https://falco.org/docs/rules/supported-fields/)) are introduced a version bump indicates that this field was not available in previous engine versions. In case a new Falco rule uses new fields, the [Falco rules](https://github.com/falcosecurity/falco/blob/master/rules/falco_rules.yaml) file needs to bump this version as well via setting `required_engine_version` to the new version.
- During development and release preparation, libs and driver reference commits are often bumped in Falco's cmake setup ([falcosecurity-libs cmake](https://github.com/falcosecurity/falco/blob/master/cmake/modules/falcosecurity-libs.cmake#L30) and [driver cmake](https://github.com/falcosecurity/falco/blob/master/cmake/modules/driver.cmake#L29)) in order to merge new Falco features. In practice they are mostly bumped at the same time referencing the same `libs` commit. However, for the official Falco build `FALCOSECURITY_LIBS_VERSION` flag that references the stable Libs version is used (read below).
- Similarly, Falco plugins versions are bumped in Falco's cmake setup ([plugins cmake](https://github.com/falcosecurity/falco/blob/master/cmake/modules/plugins.cmake)) and those versions are the ones used for the Falco release.
- At release time Plugin, Libs and Driver versions are compatible with Falco.
- If you use the standard Falco setup leveraging driver-loader, [driver-loader script](https://github.com/falcosecurity/falco/blob/master/scripts/falco-driver-loader) will fetch the kernel space artifact (object file) corresponding to the default `DRIVER_VERSION` Falco was shipped with (read more below under Libs).
```
Falco version: x.y.z (sem-ver like)
Libs version: x.y.z (sem-ver like)
Plugin API: x.y.z (sem-ver like)
Driver:
API version: x.y.z (sem-ver)
Schema version: x.y.z (sem-ver)
Default driver: x.y.z+driver (sem-ver like, indirectly encodes compatibility range in addition to default version Falco is shipped with)
```
### Libs repo
- Libs version is a git tag (`x.y.z`) and when building Falco the libs version is set via the `FALCOSECURITY_LIBS_VERSION` flag (see above).
- Driver version in and of itself is not directly tied to the Falco binary as opposed to the libs version being part of the source code used to compile Falco's userspace binary. This is because of the strict separation between userspace and kernel space artifacts, so things become a bit more interesting here. This is why the concept of a `Default driver` has been introduced to still implicitly declare the compatible driver versions. For example, if the default driver version is `2.0.0+driver`, Falco works with all driver versions >= 2.0.0 and < 3.0.0. This is a consequence of how the driver version is constructed starting from the `Driver API version` and `Driver Schema version`. Driver API and Schema versions are explained in the respective [libs driver doc](https://github.com/falcosecurity/libs/blob/master/driver/README.VERSION.md) -> Falco's `driver-loader` will always fetch the default driver, therefore a Falco release is always "shipped" with the driver version corresponding to the default driver.
- See [libs release doc](https://github.com/falcosecurity/libs/blob/master/release.md) for more information.
### Plugins repo
- Plugins version is a git tag (`x.y.z`)
- See [plugins release doc](https://github.com/falcosecurity/plugins/blob/master/release.md) for more information.

View File

@@ -1,13 +1,10 @@
if(CPACK_GENERATOR MATCHES "DEB") if(CPACK_GENERATOR MATCHES "DEB" OR CPACK_GENERATOR MATCHES "RPM")
list(APPEND CPACK_INSTALL_COMMANDS "mkdir -p _CPack_Packages/${CPACK_TOPLEVEL_TAG}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME}/usr/lib/systemd/system") list(APPEND CPACK_INSTALL_COMMANDS "mkdir -p _CPack_Packages/${CPACK_TOPLEVEL_TAG}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME}/usr/lib/systemd/system")
list(APPEND CPACK_INSTALL_COMMANDS "cp scripts/debian/falco.service _CPack_Packages/${CPACK_TOPLEVEL_TAG}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME}/usr/lib/systemd/system") list(APPEND CPACK_INSTALL_COMMANDS "cp -r scripts/systemd/falco-kmod-inject.service _CPack_Packages/${CPACK_TOPLEVEL_TAG}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME}/usr/lib/systemd/system")
list(APPEND CPACK_INSTALL_COMMANDS "cp scripts/debian/falco_inject_kmod.service _CPack_Packages/${CPACK_TOPLEVEL_TAG}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME}/usr/lib/systemd/system") list(APPEND CPACK_INSTALL_COMMANDS "cp scripts/systemd/falco-kmod.service _CPack_Packages/${CPACK_TOPLEVEL_TAG}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME}/usr/lib/systemd/system")
endif() list(APPEND CPACK_INSTALL_COMMANDS "cp scripts/systemd/falco-bpf.service _CPack_Packages/${CPACK_TOPLEVEL_TAG}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME}/usr/lib/systemd/system")
list(APPEND CPACK_INSTALL_COMMANDS "cp scripts/systemd/falco-modern-bpf.service _CPack_Packages/${CPACK_TOPLEVEL_TAG}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME}/usr/lib/systemd/system")
if(CPACK_GENERATOR MATCHES "RPM") list(APPEND CPACK_INSTALL_COMMANDS "cp scripts/systemd/falco-plugin.service _CPack_Packages/${CPACK_TOPLEVEL_TAG}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME}/usr/lib/systemd/system")
list(APPEND CPACK_INSTALL_COMMANDS "mkdir -p _CPack_Packages/${CPACK_TOPLEVEL_TAG}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME}/usr/lib/systemd/system")
list(APPEND CPACK_INSTALL_COMMANDS "cp scripts/rpm/falco.service _CPack_Packages/${CPACK_TOPLEVEL_TAG}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME}/usr/lib/systemd/system")
list(APPEND CPACK_INSTALL_COMMANDS "cp scripts/rpm/falco_inject_kmod.service _CPack_Packages/${CPACK_TOPLEVEL_TAG}/${CPACK_GENERATOR}/${CPACK_PACKAGE_FILE_NAME}/usr/lib/systemd/system")
endif() endif()
if(CPACK_GENERATOR MATCHES "TGZ") if(CPACK_GENERATOR MATCHES "TGZ")

View File

@@ -0,0 +1,30 @@
#
# Copyright (C) 2020 The Falco Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
#
include(ExternalProject)
set(STRING_VIEW_LITE_PREFIX ${CMAKE_BINARY_DIR}/string-view-lite-prefix)
set(STRING_VIEW_LITE_INCLUDE ${STRING_VIEW_LITE_PREFIX}/include)
message(STATUS "Using bundled string-view-lite in ${STRING_VIEW_LITE_INCLUDE}")
ExternalProject_Add(
string-view-lite
PREFIX ${STRING_VIEW_LITE_PREFIX}
GIT_REPOSITORY "https://github.com/martinmoene/string-view-lite.git"
GIT_TAG "v1.4.0"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
UPDATE_COMMAND ""
INSTALL_COMMAND
${CMAKE_COMMAND} -E copy ${STRING_VIEW_LITE_PREFIX}/src/string-view-lite/include/nonstd/string_view.hpp
${STRING_VIEW_LITE_INCLUDE}/nonstd/string_view.hpp)

View File

@@ -16,32 +16,18 @@ include(GetGitRevisionDescription)
# Create the falco version variable according to git index # Create the falco version variable according to git index
if(NOT FALCO_VERSION) if(NOT FALCO_VERSION)
string(STRIP "${FALCO_HASH}" FALCO_HASH)
# Try to obtain the exact git tag # Try to obtain the exact git tag
git_get_exact_tag(FALCO_TAG) git_get_exact_tag(FALCO_TAG)
if(NOT FALCO_TAG) if(NOT FALCO_TAG)
# Fetch current hash # Obtain the closest tag
get_git_head_revision(refspec FALCO_HASH) git_describe(FALCO_VERSION "--always" "--tags" "--abbrev=7")
if(NOT FALCO_HASH OR FALCO_HASH MATCHES "NOTFOUND$") # Fallback version
set(FALCO_VERSION "0.0.0") if(FALCO_VERSION MATCHES "NOTFOUND$")
else() set(FALCO_VERSION "0.0.0")
# Obtain the closest tag endif()
git_get_latest_tag(FALCO_LATEST_TAG) # Format FALCO_VERSION to be semver with prerelease and build part
if(NOT FALCO_LATEST_TAG OR FALCO_LATEST_TAG MATCHES "NOTFOUND$") string(REPLACE "-g" "+" FALCO_VERSION "${FALCO_VERSION}")
set(FALCO_VERSION "0.0.0")
else()
# Compute commit delta since tag
git_get_delta_from_tag(FALCO_DELTA ${FALCO_LATEST_TAG} ${FALCO_HASH})
if(NOT FALCO_DELTA OR FALCO_DELTA MATCHES "NOTFOUND$")
set(FALCO_VERSION "0.0.0")
else()
# Cut hash to 7 bytes
string(SUBSTRING ${FALCO_HASH} 0 7 FALCO_HASH)
# Format FALCO_VERSION to be semver with prerelease and build part
set(FALCO_VERSION
"${FALCO_LATEST_TAG}-${FALCO_DELTA}+${FALCO_HASH}")
endif()
endif()
endif()
else() else()
# A tag has been found: use it as the Falco version # A tag has been found: use it as the Falco version
set(FALCO_VERSION "${FALCO_TAG}") set(FALCO_VERSION "${FALCO_TAG}")

View File

@@ -86,36 +86,29 @@ function(get_git_head_revision _refspecvar _hashvar)
PARENT_SCOPE) PARENT_SCOPE)
endfunction() endfunction()
function(git_get_latest_tag _var) function(git_describe _var)
if(NOT GIT_FOUND) if(NOT GIT_FOUND)
find_package(Git QUIET) find_package(Git QUIET)
endif() endif()
get_git_head_revision(refspec hash)
# We use git describe --tags `git rev-list --tags --max-count=1` if(NOT GIT_FOUND)
execute_process(COMMAND set(${_var}
"${GIT_EXECUTABLE}" "GIT-NOTFOUND"
rev-list PARENT_SCOPE)
--tags return()
--max-count=1 endif()
WORKING_DIRECTORY if(NOT hash)
"${CMAKE_CURRENT_SOURCE_DIR}" set(${_var}
COMMAND tail -n1 "HEAD-HASH-NOTFOUND"
RESULT_VARIABLE PARENT_SCOPE)
res
OUTPUT_VARIABLE
tag_hash
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT res EQUAL 0)
set(out "${tag_hash}-${res}-NOTFOUND" PARENT_SCOPE)
return() return()
endif() endif()
execute_process(COMMAND execute_process(COMMAND
"${GIT_EXECUTABLE}" "${GIT_EXECUTABLE}"
describe describe
--tags ${hash}
${tag_hash} ${ARGN}
WORKING_DIRECTORY WORKING_DIRECTORY
"${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE RESULT_VARIABLE
@@ -127,108 +120,10 @@ function(git_get_latest_tag _var)
if(NOT res EQUAL 0) if(NOT res EQUAL 0)
set(out "${out}-${res}-NOTFOUND") set(out "${out}-${res}-NOTFOUND")
endif() endif()
set(${_var} "${out}" PARENT_SCOPE)
endfunction()
function(git_get_delta_from_tag _var tag hash)
if(NOT GIT_FOUND)
find_package(Git QUIET)
endif()
# Count commits in HEAD
execute_process(COMMAND
"${GIT_EXECUTABLE}"
rev-list
--count
${hash}
WORKING_DIRECTORY
"${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE
res
OUTPUT_VARIABLE
out_counter_head
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT res EQUAL 0)
set(${_var} "HEADCOUNT-NOTFOUND" PARENT_SCOPE)
return()
endif()
# Count commits in latest tag
execute_process(COMMAND
"${GIT_EXECUTABLE}"
rev-list
--count
${tag}
WORKING_DIRECTORY
"${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE
res
OUTPUT_VARIABLE
out_counter_tag
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT res EQUAL 0)
set(${_var} "TAGCOUNT-NOTFOUND" PARENT_SCOPE)
return()
endif()
execute_process(COMMAND
expr
${out_counter_head} - ${out_counter_tag}
WORKING_DIRECTORY
"${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE
res
OUTPUT_VARIABLE
out_delta
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT res EQUAL 0)
set(${_var} "DELTA-NOTFOUND" PARENT_SCOPE)
return()
endif()
set(${_var} "${out_delta}" PARENT_SCOPE)
endfunction()
function(git_describe _var)
if(NOT GIT_FOUND)
find_package(Git QUIET)
endif()
get_git_head_revision(refspec hash)
if(NOT GIT_FOUND)
set(${_var}
"GIT-NOTFOUND"
PARENT_SCOPE)
return()
endif()
if(NOT hash)
set(${_var}
"HEAD-HASH-NOTFOUND"
PARENT_SCOPE)
return()
endif()
execute_process(COMMAND
"${GIT_EXECUTABLE}"
describe
${hash}
${ARGN}
WORKING_DIRECTORY
"${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE
res
OUTPUT_VARIABLE
out
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT res EQUAL 0)
set(out "${out}-${res}-NOTFOUND")
endif()
set(${_var} set(${_var}
"${out}" "${out}"
PARENT_SCOPE) PARENT_SCOPE)
endfunction() endfunction()
function(git_get_exact_tag _var) function(git_get_exact_tag _var)

View File

@@ -26,8 +26,8 @@ else()
# In case you want to test against another driver version (or branch, or commit) just pass the variable - # In case you want to test against another driver version (or branch, or commit) just pass the variable -
# ie., `cmake -DDRIVER_VERSION=dev ..` # ie., `cmake -DDRIVER_VERSION=dev ..`
if(NOT DRIVER_VERSION) if(NOT DRIVER_VERSION)
set(DRIVER_VERSION "dd443b67c6b04464cb8ee2771af8ada8777e7fac") set(DRIVER_VERSION "43579a38cd35f1c0d2c0550c29fdbf11fb193b27")
set(DRIVER_CHECKSUM "SHA256=df373099d0f4cd4417a0103bb57f26c7412ffa86cde2bb2d579c6feba841626d") set(DRIVER_CHECKSUM "SHA256=36f0aff6e456b76c869e77e034b6bd4a358b78e66ef47c3bfc1c8e9bd27d2671")
endif() endif()
# cd /path/to/build && cmake /path/to/source # cd /path/to/build && cmake /path/to/source

View File

@@ -19,7 +19,7 @@ message(STATUS "Libs version: ${FALCOSECURITY_LIBS_VERSION}")
ExternalProject_Add( ExternalProject_Add(
falcosecurity-libs falcosecurity-libs
URL "https://github.com/falcosecurity/libs/archive/${FALCOSECURITY_LIBS_VERSION}.tar.gz" URL "https://github.com/Andreagit97/libs/archive/${FALCOSECURITY_LIBS_VERSION}.tar.gz"
URL_HASH "${FALCOSECURITY_LIBS_CHECKSUM}" URL_HASH "${FALCOSECURITY_LIBS_CHECKSUM}"
CONFIGURE_COMMAND "" CONFIGURE_COMMAND ""
BUILD_COMMAND "" BUILD_COMMAND ""

View File

@@ -27,8 +27,8 @@ else()
# In case you want to test against another falcosecurity/libs version (or branch, or commit) just pass the variable - # In case you want to test against another falcosecurity/libs version (or branch, or commit) just pass the variable -
# ie., `cmake -DFALCOSECURITY_LIBS_VERSION=dev ..` # ie., `cmake -DFALCOSECURITY_LIBS_VERSION=dev ..`
if(NOT FALCOSECURITY_LIBS_VERSION) if(NOT FALCOSECURITY_LIBS_VERSION)
set(FALCOSECURITY_LIBS_VERSION "dd443b67c6b04464cb8ee2771af8ada8777e7fac") set(FALCOSECURITY_LIBS_VERSION "43579a38cd35f1c0d2c0550c29fdbf11fb193b27")
set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=df373099d0f4cd4417a0103bb57f26c7412ffa86cde2bb2d579c6feba841626d") set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=36f0aff6e456b76c869e77e034b6bd4a358b78e66ef47c3bfc1c8e9bd27d2671")
endif() endif()
# cd /path/to/build && cmake /path/to/source # cd /path/to/build && cmake /path/to/source

View File

@@ -22,7 +22,7 @@ ENV CMAKE_VERSION=${CMAKE_VERSION}
# build toolchain # build toolchain
RUN yum -y install centos-release-scl && \ RUN yum -y install centos-release-scl && \
INSTALL_PKGS="devtoolset-7-gcc devtoolset-7-gcc-c++ devtoolset-7-toolchain devtoolset-7-libstdc++-devel llvm-toolset-7.0 glibc-static autoconf automake libtool createrepo expect git which libcurl-devel rpm-build libyaml-devel" && \ INSTALL_PKGS="devtoolset-7-gcc devtoolset-7-gcc-c++ devtoolset-7-toolchain devtoolset-7-libstdc++-devel devtoolset-7-elfutils-libelf-devel llvm-toolset-7.0 glibc-static autoconf automake libtool createrepo expect git which libcurl-devel zlib-devel rpm-build libyaml-devel" && \
yum -y install --setopt=tsflags=nodocs $INSTALL_PKGS && \ yum -y install --setopt=tsflags=nodocs $INSTALL_PKGS && \
rpm -V $INSTALL_PKGS rpm -V $INSTALL_PKGS

View File

@@ -0,0 +1,41 @@
FROM centos:7 AS build-stage
# To build Falco you need to pass the cmake option
ARG CMAKE_OPTIONS=""
ARG MAKE_JOBS=4
# Install all the dependencies
WORKDIR /
RUN yum -y install centos-release-scl; \
yum -y install devtoolset-8-gcc devtoolset-8-gcc-c++; \
source scl_source enable devtoolset-8; \
yum install -y git wget make m4 rpm-build
# With some previous cmake versions it fails when downloading `zlib` with curl in the libs building phase
RUN curl -L -o /tmp/cmake.tar.gz https://github.com/Kitware/CMake/releases/download/v3.22.5/cmake-3.22.5-linux-$(uname -m).tar.gz; \
gzip -d /tmp/cmake.tar.gz; \
tar -xpf /tmp/cmake.tar --directory=/tmp; \
cp -R /tmp/cmake-3.22.5-linux-$(uname -m)/* /usr; \
rm -rf /tmp/cmake-3.22.5-linux-$(uname -m)/
# Copy Falco folder from the build context
COPY . /source
WORKDIR /build/release
# We need `make tests` and `make all` for integration tests.
RUN source scl_source enable devtoolset-8; \
cmake ${CMAKE_OPTIONS} /source; \
make falco -j${MAKE_JOBS}; \
make package; \
make tests -j${MAKE_JOBS}; \
make all -j${MAKE_JOBS}
FROM scratch AS export-stage
ARG DEST_BUILD_DIR="/build"
COPY --from=build-stage /build/release/falco-*.tar.gz /packages/
COPY --from=build-stage /build/release/falco-*.deb /packages/
COPY --from=build-stage /build/release/falco-*.rpm /packages/
COPY --from=build-stage /build/release/ ${DEST_BUILD_DIR}

View File

@@ -0,0 +1,26 @@
FROM ubuntu:22.04 AS builder
COPY ./falco.tar.gz /
WORKDIR /
# 1. We remove the Falco directory with the name related to the version and the arch
# 2. We remove the source folder
# 3. We remove the `falco-driver-loader` binary
RUN mkdir falco; \
tar -xzf falco.tar.gz -C falco --strip-component 1; \
rm -rf /falco/usr/src; \
rm /falco/usr/bin/falco-driver-loader
# the time displayed in log messages and output messages will be in ISO 8601.
RUN sed -e 's/time_format_iso_8601: false/time_format_iso_8601: true/' < /falco/etc/falco/falco.yaml > /falco/etc/falco/falco.yaml.new; \
mv /falco/etc/falco/falco.yaml.new /falco/etc/falco/falco.yaml
FROM debian:11-slim
COPY --from=builder /falco /
ENV HOST_ROOT /host
ENV HOME /root
CMD ["/usr/bin/falco", "-o", "time_format_iso_8601=true", "--modern-bpf"]

View File

@@ -15,7 +15,7 @@ RUN if [ "$TARGETARCH" = "amd64" ] ; then curl -L -o grpcurl.tar.gz \
https://github.com/fullstorydev/grpcurl/releases/download/v1.8.6/grpcurl_1.8.6_linux_arm64.tar.gz; \ https://github.com/fullstorydev/grpcurl/releases/download/v1.8.6/grpcurl_1.8.6_linux_arm64.tar.gz; \
fi; fi;
RUN dnf install -y python-pip python docker findutils jq unzip && dnf clean all RUN dnf install -y python-pip python docker findutils jq unzip sed curl && dnf clean all
ENV PATH="/root/.local/bin/:${PATH}" ENV PATH="/root/.local/bin/:${PATH}"
RUN pip install --user avocado-framework==69.0 RUN pip install --user avocado-framework==69.0
RUN pip install --user avocado-framework-plugin-varianter-yaml-to-mux==69.0 RUN pip install --user avocado-framework-plugin-varianter-yaml-to-mux==69.0

View File

@@ -150,7 +150,6 @@ syscall_event_drops:
- alert - alert
rate: .03333 rate: .03333
max_burst: 1 max_burst: 1
simulate_drops: false
# Falco uses a shared buffer between the kernel and userspace to receive # Falco uses a shared buffer between the kernel and userspace to receive
# the events (eg., system call information) in userspace. # the events (eg., system call information) in userspace.

View File

@@ -220,7 +220,7 @@
items: [probe_rpminfo, probe_rpmverify, probe_rpmverifyfile, probe_rpmverifypackage] items: [probe_rpminfo, probe_rpmverify, probe_rpmverifyfile, probe_rpmverifypackage]
- macro: rpm_procs - macro: rpm_procs
condition: (proc.name in (rpm_binaries, openscap_rpm_binaries) or proc.name in (salt-call, salt-minion)) condition: (proc.name in (rpm_binaries, openscap_rpm_binaries) or proc.name in (salt-minion))
- list: deb_binaries - list: deb_binaries
items: [dpkg, dpkg-preconfigu, dpkg-reconfigur, dpkg-divert, apt, apt-get, aptitude, items: [dpkg, dpkg-preconfigu, dpkg-reconfigur, dpkg-divert, apt, apt-get, aptitude,
@@ -1441,7 +1441,7 @@
and not proc.name in (user_mgmt_binaries, userexec_binaries, package_mgmt_binaries, and not proc.name in (user_mgmt_binaries, userexec_binaries, package_mgmt_binaries,
cron_binaries, read_sensitive_file_binaries, shell_binaries, hids_binaries, cron_binaries, read_sensitive_file_binaries, shell_binaries, hids_binaries,
vpn_binaries, mail_config_binaries, nomachine_binaries, sshkit_script_binaries, vpn_binaries, mail_config_binaries, nomachine_binaries, sshkit_script_binaries,
in.proftpd, mandb, salt-call, salt-minion, postgres_mgmt_binaries, in.proftpd, mandb, salt-minion, postgres_mgmt_binaries,
google_oslogin_ google_oslogin_
) )
and not cmp_cp_by_passwd and not cmp_cp_by_passwd
@@ -3064,7 +3064,7 @@
- rule: Linux Kernel Module Injection Detected - rule: Linux Kernel Module Injection Detected
desc: Detect kernel module was injected (from container). desc: Detect kernel module was injected (from container).
condition: spawned_process and container and proc.name=insmod and not proc.args in (white_listed_modules) and thread.cap_effective icontains sys_module condition: spawned_process and container and proc.name=insmod and not proc.args in (white_listed_modules)
output: Linux Kernel Module injection using insmod detected (user=%user.name user_loginuid=%user.loginuid parent_process=%proc.pname module=%proc.args %container.info image=%container.image.repository:%container.image.tag) output: Linux Kernel Module injection using insmod detected (user=%user.name user_loginuid=%user.loginuid parent_process=%proc.pname module=%proc.args %container.info image=%container.image.repository:%container.image.tag)
priority: WARNING priority: WARNING
tags: [process] tags: [process]
@@ -3240,16 +3240,3 @@
command=%proc.cmdline pid=%proc.pid file=%fd.name parent=%proc.pname gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4] container_id=%container.id image=%container.image.repository) command=%proc.cmdline pid=%proc.pid file=%fd.name parent=%proc.pname gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4] container_id=%container.id image=%container.image.repository)
priority: WARNING priority: WARNING
tags: [filesystem, mitre_credential_access, mitre_discovery] tags: [filesystem, mitre_credential_access, mitre_discovery]
- list: known_ptrace_binaries
items: []
- macro: known_ptrace_procs
condition: (proc.name in (known_ptrace_binaries))
- rule: PTRACE attached to process
desc: "This rule detects an attempt to inject code into a process using PTRACE."
condition: evt.type=ptrace and evt.dir=> and evt.arg.request in (5, 6, 11, 20, 27) and proc_name_exists and not known_ptrace_procs
output: Detected ptrace PTRACE_ATTACH attempt (proc.cmdline=%proc.cmdline container=%container.info evt.type=%evt.type evt.arg.request=%evt.arg.request proc.pid=%proc.pid proc.cwd=%proc.cwd proc.ppid=%proc.ppid proc.pcmdline=%proc.pcmdline proc.sid=%proc.sid proc.exepath=%proc.exepath user.uid=%user.uid user.loginuid=%user.loginuid user.loginname=%user.loginname user.name=%user.name group.gid=%group.gid group.name=%group.name container.id=%container.id container.name=%container.name image=%container.image.repository)
priority: WARNING
tags: [process]

View File

@@ -15,26 +15,28 @@
# limitations under the License. # limitations under the License.
# #
# Systemd
file(COPY "${PROJECT_SOURCE_DIR}/scripts/systemd/falco-kmod-inject.service"
DESTINATION "${PROJECT_BINARY_DIR}/scripts/systemd")
file(COPY "${PROJECT_SOURCE_DIR}/scripts/systemd/falco-kmod.service"
DESTINATION "${PROJECT_BINARY_DIR}/scripts/systemd")
file(COPY "${PROJECT_SOURCE_DIR}/scripts/systemd/falco-bpf.service"
DESTINATION "${PROJECT_BINARY_DIR}/scripts/systemd")
file(COPY "${PROJECT_SOURCE_DIR}/scripts/systemd/falco-modern-bpf.service"
DESTINATION "${PROJECT_BINARY_DIR}/scripts/systemd")
file(COPY "${PROJECT_SOURCE_DIR}/scripts/systemd/falco-plugin.service"
DESTINATION "${PROJECT_BINARY_DIR}/scripts/systemd")
# Debian
configure_file(debian/postinst.in debian/postinst) configure_file(debian/postinst.in debian/postinst)
configure_file(debian/postrm.in debian/postrm) configure_file(debian/postrm.in debian/postrm)
configure_file(debian/prerm.in debian/prerm) configure_file(debian/prerm.in debian/prerm)
file(COPY "${PROJECT_SOURCE_DIR}/scripts/debian/falco.service" # Rpm
DESTINATION "${PROJECT_BINARY_DIR}/scripts/debian")
file(COPY "${PROJECT_SOURCE_DIR}/scripts/debian/falco_inject_kmod.service"
DESTINATION "${PROJECT_BINARY_DIR}/scripts/debian")
configure_file(rpm/postinstall.in rpm/postinstall) configure_file(rpm/postinstall.in rpm/postinstall)
configure_file(rpm/postuninstall.in rpm/postuninstall) configure_file(rpm/postuninstall.in rpm/postuninstall)
configure_file(rpm/preuninstall.in rpm/preuninstall) configure_file(rpm/preuninstall.in rpm/preuninstall)
file(COPY "${PROJECT_SOURCE_DIR}/scripts/rpm/falco.service"
DESTINATION "${PROJECT_BINARY_DIR}/scripts/rpm")
file(COPY "${PROJECT_SOURCE_DIR}/scripts/rpm/falco_inject_kmod.service"
DESTINATION "${PROJECT_BINARY_DIR}/scripts/rpm")
configure_file(falco-driver-loader falco-driver-loader @ONLY) configure_file(falco-driver-loader falco-driver-loader @ONLY)
if(CMAKE_SYSTEM_NAME MATCHES "Linux") if(CMAKE_SYSTEM_NAME MATCHES "Linux")

View File

@@ -1,13 +0,0 @@
[Unit]
Description=Falco: Container Native Runtime Security
Documentation=https://falco.org/docs/
Before=falco.service
Wants=falco.service
[Service]
Type=oneshot
User=root
ExecStart=/sbin/modprobe falco
[Install]
WantedBy=multi-user.target

View File

@@ -17,58 +17,65 @@
# #
set -e set -e
DKMS_PACKAGE_NAME="@PACKAGE_NAME@" chosen_driver=
DKMS_VERSION="@DRIVER_VERSION@"
NAME="@PACKAGE_NAME@"
postinst_found=0 if [ "$1" = "configure" ]; then
if [ -x /usr/bin/dialog ]; then
# If dialog is installed, create a dialog to let users choose the correct driver for them
CHOICE=$(dialog --clear --backtitle "Choose your preferred driver" --title "Falco driver" --menu "Choose one of the following options:" 15 40 4 \
1 "Don't start" \
2 "Kmod" \
3 "eBPF" \
4 "Modern eBPF" \
5 "Plugin" \
2>&1 >/dev/tty)
clear
case $CHOICE in
2)
chosen_driver="kmod"
;;
3)
chosen_driver="bpf"
;;
4)
chosen_driver="modern-bpf"
;;
5)
chosen_driver="plugin"
;;
esac
fi
fi
case "$1" in # If needed, try to load/compile the driver through falco-driver-loader
configure) case "$chosen_driver" in
for DKMS_POSTINST in /usr/lib/dkms/common.postinst /usr/share/$DKMS_PACKAGE_NAME/postinst; do "kmod")
if [ -f $DKMS_POSTINST ]; then echo "[POST-INSTALL] Call 'falco-driver-loader module':"
$DKMS_POSTINST $DKMS_PACKAGE_NAME $DKMS_VERSION /usr/share/$DKMS_PACKAGE_NAME "" $2 falco-driver-loader module
postinst_found=1 ;;
break "bpf")
fi echo "[POST-INSTALL] Call 'falco-driver-loader bpf':"
done falco-driver-loader bpf
if [ "$postinst_found" -eq 0 ]; then ;;
echo "ERROR: DKMS version is too old and $DKMS_PACKAGE_NAME was not"
echo "built with legacy DKMS support."
echo "You must either rebuild $DKMS_PACKAGE_NAME with legacy postinst"
echo "support or upgrade DKMS to a more current version."
exit 1
fi
;;
esac esac
# Based off what debhelper dh_systemd_enable/13.3.4 would have added
# ref: https://www.debian.org/doc/manuals/debmake-doc/ch05.en.html#debhelper
if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-deconfigure" ] || [ "$1" = "abort-remove" ] ; then if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-deconfigure" ] || [ "$1" = "abort-remove" ] ; then
# This will only remove masks created by d-s-h on package removal. if [ -n "$chosen_driver" ]; then
deb-systemd-helper unmask 'falco.service' >/dev/null || true echo "[POST-INSTALL] Enable 'falco-$chosen_driver.service':"
systemctl --system enable "falco-$chosen_driver.service" || true
# was-enabled defaults to true, so new installations run enable. echo "[POST-INSTALL] Start 'falco-$chosen_driver.service':"
if deb-systemd-helper --quiet was-enabled 'falco.service'; then systemctl --system start "falco-$chosen_driver.service" || true
# Enables the unit on first installation, creates new
# symlinks on upgrades if the unit file has changed.
deb-systemd-helper enable 'falco.service' >/dev/null || true
else
# Update the statefile to add new symlinks (if any), which need to be
# cleaned up on purge. Also remove old symlinks.
deb-systemd-helper update-state 'falco.service' >/dev/null || true
fi fi
fi fi
if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-deconfigure" ] || [ "$1" = "abort-remove" ] ; then if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-deconfigure" ] || [ "$1" = "abort-remove" ] ; then
if [ -d /run/systemd/system ]; then if [ -d /run/systemd/system ]; then
systemctl --system daemon-reload >/dev/null || true echo "[POST-INSTALL] Trigger deamon-reload:"
if [ -n "$2" ]; then systemctl --system daemon-reload || true
_dh_action=restart if [ -n "$chosen_driver" ]; then
else echo "[POST-INSTALL] Trigger 'falco-$chosen_driver.service' condrestart:"
_dh_action=start # restart falco on upgrade if service is already running
fi systemctl --system condrestart "falco-$chosen_driver.service" || true
deb-systemd-invoke $_dh_action 'falco.service' >/dev/null || true fi
fi fi
fi fi

View File

@@ -22,18 +22,11 @@
set -e set -e
if [ -d /run/systemd/system ] && [ "$1" = remove ]; then if [ -d /run/systemd/system ] && [ "$1" = remove ]; then
systemctl --system daemon-reload >/dev/null || true echo "[POST-REMOVE] Disable all Falco services:"
fi systemctl --system disable 'falco-kmod.service' || true
systemctl --system disable 'falco-bpf.service' || true
if [ "$1" = "remove" ]; then systemctl --system disable 'falco-modern-bpf.service' || true
if [ -x "/usr/bin/deb-systemd-helper" ]; then systemctl --system disable 'falco-plugin.service' || true
deb-systemd-helper mask 'falco.service' >/dev/null || true echo "[POST-REMOVE] Trigger deamon-reload:"
fi systemctl --system daemon-reload || true
fi
if [ "$1" = "purge" ]; then
if [ -x "/usr/bin/deb-systemd-helper" ]; then
deb-systemd-helper purge 'falco.service' >/dev/null || true
deb-systemd-helper unmask 'falco.service' >/dev/null || true
fi
fi fi

View File

@@ -22,11 +22,18 @@ set -e
# Currently running falco service uses the driver, so stop it before driver cleanup # Currently running falco service uses the driver, so stop it before driver cleanup
if [ -d /run/systemd/system ] && [ "$1" = remove ]; then if [ -d /run/systemd/system ] && [ "$1" = remove ]; then
deb-systemd-invoke stop 'falco.service' >/dev/null || true echo "[PRE-REMOVE] Stop all Falco services:"
systemctl --system stop 'falco-kmod.service' || true
systemctl --system stop 'falco-bpf.service' || true
systemctl --system stop 'falco-modern-bpf.service' || true
systemctl --system stop 'falco-plugin.service' || true
# this should be stopped after 'falco-kmod.service'
systemctl --system stop 'falco-kmod-inject.service' || true
fi fi
case "$1" in case "$1" in
remove|upgrade|deconfigure) remove|upgrade|deconfigure)
/usr/bin/falco-driver-loader --clean echo "[PRE-REMOVE] Call 'falco-driver-loader --clean:'"
falco-driver-loader --clean
;; ;;
esac esac

View File

@@ -211,7 +211,13 @@ load_kernel_module_compile() {
fi fi
# Try to compile using all the available gcc versions # Try to compile using all the available gcc versions
for CURRENT_GCC in $(which gcc) $(ls "$(dirname "$(which gcc)")"/gcc-* | grep 'gcc-[0-9]\+' | sort -n -r -k 2 -t -); do for CURRENT_GCC in $(ls "$(dirname "$(which gcc)")"/gcc*); do
# Filter away gcc-{ar,nm,...}
# Only gcc compiler has `-print-search-dirs` option.
${CURRENT_GCC} -print-search-dirs 2>&1 | grep "install:"
if [ "$?" -ne "0" ]; then
continue
fi
echo "* Trying to dkms install ${DRIVER_NAME} module with GCC ${CURRENT_GCC}" echo "* Trying to dkms install ${DRIVER_NAME} module with GCC ${CURRENT_GCC}"
echo "#!/usr/bin/env bash" > /tmp/falco-dkms-make echo "#!/usr/bin/env bash" > /tmp/falco-dkms-make
echo "make CC=${CURRENT_GCC} \$@" >> /tmp/falco-dkms-make echo "make CC=${CURRENT_GCC} \$@" >> /tmp/falco-dkms-make
@@ -232,14 +238,19 @@ load_kernel_module_compile() {
return return
fi fi
echo "* ${DRIVER_NAME} module found: ${KO_FILE}" echo "* ${DRIVER_NAME} module found: ${KO_FILE}"
echo "* Trying insmod" echo "* Trying to modprobe"
chcon -t modules_object_t "$KO_FILE" > /dev/null 2>&1 || true chcon -t modules_object_t "$KO_FILE" > /dev/null 2>&1 || true
if insmod "$KO_FILE" > /dev/null 2>&1; then if modprobe "${DRIVER_NAME}" > /dev/null 2>&1; then
echo "* Success: ${DRIVER_NAME} module found and loaded in dkms" echo "* Success: ${DRIVER_NAME} module found in dkms and loaded"
exit 0 exit 0
else
echo "* Unable to insmod ${DRIVER_NAME} module"
fi fi
echo "* Unable to load ${DRIVER_NAME} module"
echo "* Trying insmod"
if insmod "$KO_FILE" > /dev/null 2>&1; then
echo "* Success: ${DRIVER_NAME} module found in dkms and inserted"
exit 0
fi
echo "* Unable to insmod ${DRIVER_NAME} module"
else else
DKMS_LOG="/var/lib/dkms/${DRIVER_NAME}/${DRIVER_VERSION}/build/make.log" DKMS_LOG="/var/lib/dkms/${DRIVER_NAME}/${DRIVER_VERSION}/build/make.log"
if [ -f "${DKMS_LOG}" ]; then if [ -f "${DKMS_LOG}" ]; then
@@ -260,12 +271,19 @@ load_kernel_module_download() {
if curl -L --create-dirs "${FALCO_DRIVER_CURL_OPTIONS}" -o "${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${FALCO_KERNEL_MODULE_FILENAME}" "${URL}"; then if curl -L --create-dirs "${FALCO_DRIVER_CURL_OPTIONS}" -o "${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${FALCO_KERNEL_MODULE_FILENAME}" "${URL}"; then
echo "* Download succeeded" echo "* Download succeeded"
chcon -t modules_object_t "${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${FALCO_KERNEL_MODULE_FILENAME}" > /dev/null 2>&1 || true chcon -t modules_object_t "${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${FALCO_KERNEL_MODULE_FILENAME}" > /dev/null 2>&1 || true
mkdir -p /lib/modules/${KERNEL_RELEASE}/kernel/drivers/falco/
cp ${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${FALCO_KERNEL_MODULE_FILENAME} /lib/modules/${KERNEL_RELEASE}/kernel/drivers/falco/falco.ko
depmod ${KERNEL_RELEASE}
if modprobe "${DRIVER_NAME}" > /dev/null 2>&1; then
echo "* Success: ${DRIVER_NAME} module found and loaded"
exit 0
fi
>&2 echo "Unable to load the prebuilt ${DRIVER_NAME} module"
if insmod "${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${FALCO_KERNEL_MODULE_FILENAME}"; then if insmod "${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${FALCO_KERNEL_MODULE_FILENAME}"; then
echo "* Success: ${DRIVER_NAME} module found and inserted" echo "* Success: ${DRIVER_NAME} module found and inserted"
exit 0 exit 0
else fi
>&2 echo "Unable to insmod the prebuilt ${DRIVER_NAME} module" >&2 echo "Unable to insmod the prebuilt ${DRIVER_NAME} module"
fi
else else
>&2 echo "Unable to find a prebuilt ${DRIVER_NAME} module" >&2 echo "Unable to find a prebuilt ${DRIVER_NAME} module"
return return
@@ -379,6 +397,13 @@ load_kernel_module() {
if [ -f "${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${FALCO_KERNEL_MODULE_FILENAME}" ]; then if [ -f "${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${FALCO_KERNEL_MODULE_FILENAME}" ]; then
echo "* Found a prebuilt ${DRIVER_NAME} module at ${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${FALCO_KERNEL_MODULE_FILENAME}, loading it" echo "* Found a prebuilt ${DRIVER_NAME} module at ${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${FALCO_KERNEL_MODULE_FILENAME}, loading it"
chcon -t modules_object_t "${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${FALCO_KERNEL_MODULE_FILENAME}" > /dev/null 2>&1 || true chcon -t modules_object_t "${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${FALCO_KERNEL_MODULE_FILENAME}" > /dev/null 2>&1 || true
mkdir -p /lib/modules/${KERNEL_RELEASE}/kernel/drivers/falco/ || true
cp ${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${FALCO_KERNEL_MODULE_FILENAME} /lib/modules/${KERNEL_RELEASE}/kernel/drivers/falco/falco.ko || true
depmod ${KERNEL_RELEASE}
if modprobe "${DRIVER_NAME}" > /dev/null 2>&1; then
echo "* Success: ${DRIVER_NAME} module found and loaded"
exit 0
fi
insmod "${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${FALCO_KERNEL_MODULE_FILENAME}" && echo "* Success: ${DRIVER_NAME} module found and inserted" insmod "${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${FALCO_KERNEL_MODULE_FILENAME}" && echo "* Success: ${DRIVER_NAME} module found and inserted"
exit $? exit $?
fi fi
@@ -397,7 +422,7 @@ load_kernel_module() {
# Last try (might load a previous driver version) # Last try (might load a previous driver version)
echo "* Trying to load a system ${DRIVER_NAME} module, if present" echo "* Trying to load a system ${DRIVER_NAME} module, if present"
if modprobe "${DRIVER_NAME}" > /dev/null 2>&1; then if modprobe "${DRIVER_NAME}" > /dev/null 2>&1; then
echo "* Success: ${DRIVER_NAME} module found and loaded with modprobe" echo "* Success: ${DRIVER_NAME} module found and loaded"
exit 0 exit 0
fi fi

View File

@@ -1,13 +0,0 @@
[Unit]
Description=Falco: Container Native Runtime Security
Documentation=https://falco.org/docs/
Before=falco.service
Wants=falco.service
[Service]
Type=oneshot
User=root
ExecStart=/sbin/modprobe falco
[Install]
WantedBy=multi-user.target

View File

@@ -16,21 +16,48 @@
# #
set -e set -e
mod_version="@DRIVER_VERSION@" chosen_driver=
dkms add -m falco -v $mod_version --rpm_safe_upgrade
if [ `uname -r | grep -c "BOOT"` -eq 0 ] && [ -e /lib/modules/`uname -r`/build/include ]; then if [ $1 -eq 1 ]; then
dkms build -m falco -v $mod_version if [ -x /usr/bin/dialog ]; then
dkms install --force -m falco -v $mod_version # If dialog is installed, create a dialog to let users choose the correct driver for them
elif [ `uname -r | grep -c "BOOT"` -gt 0 ]; then CHOICE=$(dialog --clear --backtitle "Choose your preferred driver" --title "Falco driver" --menu "Choose one of the following options:" 15 40 4 \
echo -e "" 1 "Don't start" \
echo -e "Module build for the currently running kernel was skipped since you" 2 "Kmod" \
echo -e "are running a BOOT variant of the kernel." 3 "eBPF" \
else 4 "Modern eBPF" \
echo -e "" 5 "Plugin" \
echo -e "Module build for the currently running kernel was skipped since the" 2>&1 >/dev/tty)
echo -e "kernel source for this kernel does not seem to be installed." clear
case $CHOICE in
2)
chosen_driver="kmod"
;;
3)
chosen_driver="bpf"
;;
4)
chosen_driver="modern-bpf"
;;
5)
chosen_driver="plugin"
;;
esac
fi
fi fi
# If needed, try to load/compile the driver through falco-driver-loader
case "$chosen_driver" in
"kmod")
echo "[POST-INSTALL] Call 'falco-driver-loader module':"
falco-driver-loader module
;;
"bpf")
echo "[POST-INSTALL] Call 'falco-driver-loader bpf':"
falco-driver-loader bpf
;;
esac
# validate rpm macros by `rpm -qp --scripts <rpm>` # validate rpm macros by `rpm -qp --scripts <rpm>`
# RPM scriptlets: https://docs.fedoraproject.org/en-US/packaging-guidelines/Scriptlets/#_systemd # RPM scriptlets: https://docs.fedoraproject.org/en-US/packaging-guidelines/Scriptlets/#_systemd
# https://docs.fedoraproject.org/en-US/packaging-guidelines/Scriptlets/#_syntax # https://docs.fedoraproject.org/en-US/packaging-guidelines/Scriptlets/#_syntax
@@ -38,27 +65,27 @@ fi
# systemd_post macro expands to # systemd_post macro expands to
# if postinst: # if postinst:
# `systemd-update-helper install-system-units <service>` # `systemd-update-helper install-system-units <service>`
%systemd_post 'falco.service' %systemd_post "falco-$chosen_driver.service"
# post install mirrored from .deb # post install mirrored from .deb
if [ $1 -eq 1 ]; then if [ $1 -eq 1 ]; then
# This will only remove masks created on package removal. if [ -n "$chosen_driver" ]; then
/usr/bin/systemctl --system unmask 'falco.service' >/dev/null || true echo "[POST-INSTALL] Enable 'falco-$chosen_driver.service':"
systemctl --system enable "falco-$chosen_driver.service" || true
# enable falco on installation echo "[POST-INSTALL] Start 'falco-$chosen_driver.service':"
# note: DEB postinstall script checks for changed symlinks systemctl --system start "falco-$chosen_driver.service" || true
/usr/bin/systemctl --system enable 'falco.service' >/dev/null || true fi
# start falco on installation
/usr/bin/systemctl --system start 'falco.service' >/dev/null || true
fi fi
# post upgrade mirrored from .deb # post upgrade mirrored from .deb
if [ $1 -gt 1 ]; then if [ $1 -gt 1 ]; then
if [ -d /run/systemd/system ]; then if [ -d /run/systemd/system ]; then
/usr/bin/systemctl --system daemon-reload >/dev/null || true echo "[POST-INSTALL] Trigger deamon-reload:"
systemctl --system daemon-reload || true
# restart falco on upgrade if service is already running if [ -n "$chosen_driver" ]; then
/usr/bin/systemctl --system condrestart 'falco.service' >/dev/null || true echo "[POST-INSTALL] Trigger 'falco-$chosen_driver.service' condrestart:"
# restart falco on upgrade if service is already running
systemctl --system condrestart "falco-$chosen_driver.service" || true
fi
fi fi
fi fi

View File

@@ -17,17 +17,12 @@
set -e set -e
# post uninstall mirrored from .deb if [ -d /run/systemd/system ] && [ $1 -eq 0 ]; then
if [ -d /run/systemd/system ] && [ "$1" = 0 ]; then echo "[POST-REMOVE] Disable all Falco services:"
/usr/bin/systemctl --system daemon-reload >/dev/null || true systemctl --system disable 'falco-kmod.service'|| true
/usr/bin/systemctl --system mask 'falco.service' >/dev/null || true systemctl --system disable 'falco-bpf.service' || true
systemctl --system disable 'falco-modern-bpf.service' || true
systemctl --system disable 'falco-plugin.service' || true
echo "[POST-REMOVE] Trigger deamon-reload:"
systemctl --system daemon-reload || true
fi fi
# validate rpm macros by `rpm -qp --scripts <rpm>`
# RPM scriptlets: https://docs.fedoraproject.org/en-US/packaging-guidelines/Scriptlets/#_systemd
# https://docs.fedoraproject.org/en-US/packaging-guidelines/Scriptlets/#_syntax
# systemd_postun_with_restart macro expands to
# if package upgrade, not uninstall:
# `systemd-update-helper mark-restart-system-units <service>`
%systemd_postun_with_restart 'falco.service'

View File

@@ -19,11 +19,17 @@ set -e
# pre uninstall mirrored from .deb # pre uninstall mirrored from .deb
# Currently running falco service uses the driver, so stop it before driver cleanup # Currently running falco service uses the driver, so stop it before driver cleanup
if [ -d /run/systemd/system ] && [ $1 -eq 0 ]; then if [ -d /run/systemd/system ] && [ $1 -eq 0 ]; then
# stop falco service before uninstall echo "[PRE-REMOVE] Stop all Falco services:"
/usr/bin/systemctl --system stop 'falco.service' >/dev/null || true systemctl --system stop 'falco-kmod.service' || true
systemctl --system stop 'falco-bpf.service' || true
systemctl --system stop 'falco-modern-bpf.service' || true
systemctl --system stop 'falco-plugin.service' || true
# this should be stopped after 'falco-kmod.service'
systemctl --system stop 'falco-kmod-inject.service' || true
fi fi
/usr/bin/falco-driver-loader --clean echo "[PRE-REMOVE] Call 'falco-driver-loader --clean:'"
falco-driver-loader --clean
# validate rpm macros by `rpm -qp --scripts <rpm>` # validate rpm macros by `rpm -qp --scripts <rpm>`
# RPM scriptlets: https://docs.fedoraproject.org/en-US/packaging-guidelines/Scriptlets/#_systemd # RPM scriptlets: https://docs.fedoraproject.org/en-US/packaging-guidelines/Scriptlets/#_systemd
@@ -32,4 +38,7 @@ fi
# systemd_preun macro expands to # systemd_preun macro expands to
# if preuninstall: # if preuninstall:
# `systemd-update-helper remove-system-units <service>` # `systemd-update-helper remove-system-units <service>`
%systemd_preun 'falco.service' %systemd_preun 'falco-kmod.service'
%systemd_preun 'falco-bpf.service'
%systemd_preun 'falco-modern-bpf.service'
%systemd_preun 'falco-plugin.service'

View File

@@ -1,14 +1,15 @@
[Unit] [Unit]
Description=Falco: Container Native Runtime Security Description=Falco: Container Native Runtime Security with ebpf
Documentation=https://falco.org/docs/ Documentation=https://falco.org/docs/
After=falco_inject_kmod.service Conflicts=falco-kmod.service
Requires=falco_inject_kmod.service Conflicts=falco-modern-bpf.service
Conflicts=falco-plugin.service
[Service] [Service]
Type=simple Type=simple
User=root User=root
Environment=FALCO_BPF_PROBE=
ExecStart=/usr/bin/falco --pidfile=/var/run/falco.pid ExecStart=/usr/bin/falco --pidfile=/var/run/falco.pid
ExecStopPost=/sbin/rmmod falco
UMask=0077 UMask=0077
TimeoutSec=30 TimeoutSec=30
RestartSec=15s RestartSec=15s
@@ -18,7 +19,6 @@ NoNewPrivileges=yes
ProtectHome=read-only ProtectHome=read-only
ProtectSystem=full ProtectSystem=full
ProtectKernelTunables=true ProtectKernelTunables=true
ReadWritePaths=/sys/module/falco
RestrictRealtime=true RestrictRealtime=true
RestrictAddressFamilies=~AF_PACKET RestrictAddressFamilies=~AF_PACKET
StandardOutput=null StandardOutput=null

View File

@@ -0,0 +1,8 @@
[Unit]
Description=Falco: Container Native Runtime Security with kmod, inject.
Documentation=https://falco.org/docs/
[Service]
Type=oneshot
User=root
ExecStart=/sbin/modprobe falco

View File

@@ -0,0 +1,30 @@
[Unit]
Description=Falco: Container Native Runtime Security with kmod
Documentation=https://falco.org/docs/
After=falco-kmod-inject.service
Requires=falco-kmod-inject.service
Conflicts=falco-bpf.service
Conflicts=falco-modern-bpf.service
Conflicts=falco-plugin.service
[Service]
Type=simple
User=root
ExecStart=/usr/bin/falco --pidfile=/var/run/falco.pid
ExecStopPost=/sbin/rmmod falco
UMask=0077
TimeoutSec=30
RestartSec=15s
Restart=on-failure
PrivateTmp=true
NoNewPrivileges=yes
ProtectHome=read-only
ProtectSystem=full
ProtectKernelTunables=true
ReadWritePaths=/sys/module/falco
RestrictRealtime=true
RestrictAddressFamilies=~AF_PACKET
StandardOutput=null
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,26 @@
[Unit]
Description=Falco: Container Native Runtime Security with modern ebpf
Documentation=https://falco.org/docs/
Conflicts=falco-kmod.service
Conflicts=falco-bpf.service
Conflicts=falco-plugin.service
[Service]
Type=simple
User=root
ExecStart=/usr/bin/falco --pidfile=/var/run/falco.pid --modern-bpf
UMask=0077
TimeoutSec=30
RestartSec=15s
Restart=on-failure
PrivateTmp=true
NoNewPrivileges=yes
ProtectHome=read-only
ProtectSystem=full
ProtectKernelTunables=true
RestrictRealtime=true
RestrictAddressFamilies=~AF_PACKET
StandardOutput=null
[Install]
WantedBy=multi-user.target

View File

@@ -1,14 +1,14 @@
[Unit] [Unit]
Description=Falco: Container Native Runtime Security Description=Falco: Container Native Runtime Security with plugin
Documentation=https://falco.org/docs/ Documentation=https://falco.org/docs/
After=falco_inject_kmod.service Conflicts=falco-kmod.service
Requires=falco_inject_kmod.service Conflicts=falco-bpf.service
Conflicts=falco-modern-bpf.service
[Service] [Service]
Type=simple Type=simple
User=root User=%u
ExecStart=/usr/bin/falco --pidfile=/var/run/falco.pid ExecStart=/usr/bin/falco --pidfile=/var/run/falco.pid
ExecStopPost=/sbin/rmmod falco
UMask=0077 UMask=0077
TimeoutSec=30 TimeoutSec=30
RestartSec=15s RestartSec=15s
@@ -18,9 +18,9 @@ NoNewPrivileges=yes
ProtectHome=read-only ProtectHome=read-only
ProtectSystem=full ProtectSystem=full
ProtectKernelTunables=true ProtectKernelTunables=true
ReadWritePaths=/sys/module/falco
RestrictRealtime=true RestrictRealtime=true
RestrictAddressFamilies=~AF_PACKET RestrictAddressFamilies=~AF_PACKET
StandardOutput=null
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target

View File

@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
#include "falco_utils.h" #include "falco_utils.h"
#include <nonstd/string_view.hpp>
#include <catch.hpp> #include <catch.hpp>
TEST_CASE("is_unix_scheme matches", "[utils]") TEST_CASE("is_unix_scheme matches", "[utils]")

View File

@@ -20,27 +20,9 @@ limitations under the License.
using namespace std; using namespace std;
using namespace libsinsp::filter::ast; using namespace libsinsp::filter::ast;
static pos_info create_pos(uint32_t idx, uint32_t line, uint32_t col)
{
pos_info ret;
ret.idx = idx;
ret.line = line;
ret.col = col;
return ret;
}
static bool operator==(const pos_info& p1, const pos_info& p2)
{
return (p1.idx == p2.idx) &&
(p1.line == p2.line) &&
(p1.col == p2.col);
}
TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]") TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
{ {
string macro_name = "test_macro"; string macro_name = "test_macro";
pos_info macro_pos = create_pos(12, 85, 27);
SECTION("in the general case") SECTION("in the general case")
{ {
@@ -49,7 +31,7 @@ TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
std::vector<std::unique_ptr<expr>> filter_and; std::vector<std::unique_ptr<expr>> filter_and;
filter_and.push_back(unary_check_expr::create("evt.name", "", "exists")); filter_and.push_back(unary_check_expr::create("evt.name", "", "exists"));
filter_and.push_back(not_expr::create(value_expr::create(macro_name, macro_pos))); filter_and.push_back(not_expr::create(value_expr::create(macro_name)));
std::shared_ptr<expr> filter = std::move(and_expr::create(filter_and)); std::shared_ptr<expr> filter = std::move(and_expr::create(filter_and));
std::vector<std::unique_ptr<expr>> expected_and; std::vector<std::unique_ptr<expr>> expected_and;
@@ -63,8 +45,7 @@ TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
// first run // first run
REQUIRE(resolver.run(filter) == true); REQUIRE(resolver.run(filter) == true);
REQUIRE(resolver.get_resolved_macros().size() == 1); REQUIRE(resolver.get_resolved_macros().size() == 1);
REQUIRE(resolver.get_resolved_macros().begin()->first == macro_name); REQUIRE(*resolver.get_resolved_macros().begin() == macro_name);
REQUIRE(resolver.get_resolved_macros().begin()->second == macro_pos);
REQUIRE(resolver.get_unknown_macros().empty()); REQUIRE(resolver.get_unknown_macros().empty());
REQUIRE(filter->is_equal(expected.get())); REQUIRE(filter->is_equal(expected.get()));
@@ -80,7 +61,7 @@ TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
std::shared_ptr<expr> macro = std::move( std::shared_ptr<expr> macro = std::move(
unary_check_expr::create("test.field", "", "exists")); unary_check_expr::create("test.field", "", "exists"));
std::shared_ptr<expr> filter = std::move(value_expr::create(macro_name, macro_pos)); std::shared_ptr<expr> filter = std::move(value_expr::create(macro_name));
filter_macro_resolver resolver; filter_macro_resolver resolver;
resolver.set_macro(macro_name, macro); resolver.set_macro(macro_name, macro);
@@ -90,8 +71,7 @@ TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
REQUIRE(resolver.run(filter) == true); REQUIRE(resolver.run(filter) == true);
REQUIRE(filter.get() != old_filter_ptr); REQUIRE(filter.get() != old_filter_ptr);
REQUIRE(resolver.get_resolved_macros().size() == 1); REQUIRE(resolver.get_resolved_macros().size() == 1);
REQUIRE(resolver.get_resolved_macros().begin()->first == macro_name); REQUIRE(*resolver.get_resolved_macros().begin() == macro_name);
REQUIRE(resolver.get_resolved_macros().begin()->second == macro_pos);
REQUIRE(resolver.get_unknown_macros().empty()); REQUIRE(resolver.get_unknown_macros().empty());
REQUIRE(filter->is_equal(macro.get())); REQUIRE(filter->is_equal(macro.get()));
@@ -109,17 +89,14 @@ TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
string a_macro_name = macro_name + "_1"; string a_macro_name = macro_name + "_1";
string b_macro_name = macro_name + "_2"; string b_macro_name = macro_name + "_2";
pos_info a_macro_pos = create_pos(11, 75, 43);
pos_info b_macro_pos = create_pos(91, 21, 9);
std::shared_ptr<expr> a_macro = std::move( std::shared_ptr<expr> a_macro = std::move(
unary_check_expr::create("one.field", "", "exists")); unary_check_expr::create("one.field", "", "exists"));
std::shared_ptr<expr> b_macro = std::move( std::shared_ptr<expr> b_macro = std::move(
unary_check_expr::create("another.field", "", "exists")); unary_check_expr::create("another.field", "", "exists"));
std::vector<std::unique_ptr<expr>> filter_or; std::vector<std::unique_ptr<expr>> filter_or;
filter_or.push_back(value_expr::create(a_macro_name, a_macro_pos)); filter_or.push_back(value_expr::create(a_macro_name));
filter_or.push_back(value_expr::create(b_macro_name, b_macro_pos)); filter_or.push_back(value_expr::create(b_macro_name));
std::shared_ptr<expr> filter = std::move(or_expr::create(filter_or)); std::shared_ptr<expr> filter = std::move(or_expr::create(filter_or));
std::vector<std::unique_ptr<expr>> expected_or; std::vector<std::unique_ptr<expr>> expected_or;
@@ -134,16 +111,11 @@ TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
// first run // first run
REQUIRE(resolver.run(filter) == true); REQUIRE(resolver.run(filter) == true);
REQUIRE(resolver.get_resolved_macros().size() == 2); REQUIRE(resolver.get_resolved_macros().size() == 2);
auto a_resolved_itr = resolver.get_resolved_macros().find(a_macro_name); REQUIRE(resolver.get_resolved_macros().find(a_macro_name)
REQUIRE(a_resolved_itr != resolver.get_resolved_macros().end()); != resolver.get_resolved_macros().end());
REQUIRE(a_resolved_itr->first == a_macro_name); REQUIRE(resolver.get_resolved_macros().find(b_macro_name)
REQUIRE(a_resolved_itr->second == a_macro_pos); != resolver.get_resolved_macros().end());
auto b_resolved_itr = resolver.get_resolved_macros().find(b_macro_name);
REQUIRE(b_resolved_itr != resolver.get_resolved_macros().end());
REQUIRE(resolver.get_unknown_macros().empty()); REQUIRE(resolver.get_unknown_macros().empty());
REQUIRE(b_resolved_itr->first == b_macro_name);
REQUIRE(b_resolved_itr->second == b_macro_pos);
REQUIRE(filter->is_equal(expected_filter.get())); REQUIRE(filter->is_equal(expected_filter.get()));
// second run // second run
@@ -158,18 +130,15 @@ TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
string a_macro_name = macro_name + "_1"; string a_macro_name = macro_name + "_1";
string b_macro_name = macro_name + "_2"; string b_macro_name = macro_name + "_2";
pos_info a_macro_pos = create_pos(47, 1, 76);
pos_info b_macro_pos = create_pos(111, 65, 2);
std::vector<std::unique_ptr<expr>> a_macro_and; std::vector<std::unique_ptr<expr>> a_macro_and;
a_macro_and.push_back(unary_check_expr::create("one.field", "", "exists")); a_macro_and.push_back(unary_check_expr::create("one.field", "", "exists"));
a_macro_and.push_back(value_expr::create(b_macro_name, b_macro_pos)); a_macro_and.push_back(value_expr::create(b_macro_name));
std::shared_ptr<expr> a_macro = std::move(and_expr::create(a_macro_and)); std::shared_ptr<expr> a_macro = std::move(and_expr::create(a_macro_and));
std::shared_ptr<expr> b_macro = std::move( std::shared_ptr<expr> b_macro = std::move(
unary_check_expr::create("another.field", "", "exists")); unary_check_expr::create("another.field", "", "exists"));
std::shared_ptr<expr> filter = std::move(value_expr::create(a_macro_name, a_macro_pos)); std::shared_ptr<expr> filter = std::move(value_expr::create(a_macro_name));
std::vector<std::unique_ptr<expr>> expected_and; std::vector<std::unique_ptr<expr>> expected_and;
expected_and.push_back(unary_check_expr::create("one.field", "", "exists")); expected_and.push_back(unary_check_expr::create("one.field", "", "exists"));
@@ -183,17 +152,10 @@ TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
// first run // first run
REQUIRE(resolver.run(filter) == true); REQUIRE(resolver.run(filter) == true);
REQUIRE(resolver.get_resolved_macros().size() == 2); REQUIRE(resolver.get_resolved_macros().size() == 2);
auto a_resolved_itr = resolver.get_resolved_macros().find(a_macro_name); REQUIRE(resolver.get_resolved_macros().find(a_macro_name)
REQUIRE(a_resolved_itr != resolver.get_resolved_macros().end()); != resolver.get_resolved_macros().end());
REQUIRE(a_resolved_itr->first == a_macro_name); REQUIRE(resolver.get_resolved_macros().find(b_macro_name)
REQUIRE(a_resolved_itr->second == a_macro_pos); != resolver.get_resolved_macros().end());
auto b_resolved_itr = resolver.get_resolved_macros().find(b_macro_name);
REQUIRE(b_resolved_itr != resolver.get_resolved_macros().end());
REQUIRE(resolver.get_unknown_macros().empty());
REQUIRE(b_resolved_itr->first == b_macro_name);
REQUIRE(b_resolved_itr->second == b_macro_pos);
REQUIRE(resolver.get_unknown_macros().empty()); REQUIRE(resolver.get_unknown_macros().empty());
REQUIRE(filter->is_equal(expected_filter.get())); REQUIRE(filter->is_equal(expected_filter.get()));
@@ -208,20 +170,18 @@ TEST_CASE("Should resolve macros on a filter AST", "[rule_loader]")
TEST_CASE("Should find unknown macros", "[rule_loader]") TEST_CASE("Should find unknown macros", "[rule_loader]")
{ {
string macro_name = "test_macro"; string macro_name = "test_macro";
pos_info macro_pos = create_pos(9, 4, 2);
SECTION("in the general case") SECTION("in the general case")
{ {
std::vector<std::unique_ptr<expr>> filter_and; std::vector<std::unique_ptr<expr>> filter_and;
filter_and.push_back(unary_check_expr::create("evt.name", "", "exists")); filter_and.push_back(unary_check_expr::create("evt.name", "", "exists"));
filter_and.push_back(not_expr::create(value_expr::create(macro_name, macro_pos))); filter_and.push_back(not_expr::create(value_expr::create(macro_name)));
std::shared_ptr<expr> filter = std::move(and_expr::create(filter_and)); std::shared_ptr<expr> filter = std::move(and_expr::create(filter_and));
filter_macro_resolver resolver; filter_macro_resolver resolver;
REQUIRE(resolver.run(filter) == false); REQUIRE(resolver.run(filter) == false);
REQUIRE(resolver.get_unknown_macros().size() == 1); REQUIRE(resolver.get_unknown_macros().size() == 1);
REQUIRE(resolver.get_unknown_macros().begin()->first == macro_name); REQUIRE(*resolver.get_unknown_macros().begin() == macro_name);
REQUIRE(resolver.get_unknown_macros().begin()->second == macro_pos);
REQUIRE(resolver.get_resolved_macros().empty()); REQUIRE(resolver.get_resolved_macros().empty());
} }
@@ -230,15 +190,12 @@ TEST_CASE("Should find unknown macros", "[rule_loader]")
string a_macro_name = macro_name + "_1"; string a_macro_name = macro_name + "_1";
string b_macro_name = macro_name + "_2"; string b_macro_name = macro_name + "_2";
pos_info a_macro_pos = create_pos(32, 84, 9);
pos_info b_macro_pos = create_pos(1, 0, 5);
std::vector<std::unique_ptr<expr>> a_macro_and; std::vector<std::unique_ptr<expr>> a_macro_and;
a_macro_and.push_back(unary_check_expr::create("one.field", "", "exists")); a_macro_and.push_back(unary_check_expr::create("one.field", "", "exists"));
a_macro_and.push_back(value_expr::create(b_macro_name, b_macro_pos)); a_macro_and.push_back(value_expr::create(b_macro_name));
std::shared_ptr<expr> a_macro = std::move(and_expr::create(a_macro_and)); std::shared_ptr<expr> a_macro = std::move(and_expr::create(a_macro_and));
std::shared_ptr<expr> filter = std::move(value_expr::create(a_macro_name, a_macro_pos)); std::shared_ptr<expr> filter = std::move(value_expr::create(a_macro_name));
auto expected_filter = clone(a_macro.get()); auto expected_filter = clone(a_macro.get());
filter_macro_resolver resolver; filter_macro_resolver resolver;
@@ -247,11 +204,9 @@ TEST_CASE("Should find unknown macros", "[rule_loader]")
// first run // first run
REQUIRE(resolver.run(filter) == true); REQUIRE(resolver.run(filter) == true);
REQUIRE(resolver.get_resolved_macros().size() == 1); REQUIRE(resolver.get_resolved_macros().size() == 1);
REQUIRE(resolver.get_resolved_macros().begin()->first == a_macro_name); REQUIRE(*resolver.get_resolved_macros().begin() == a_macro_name);
REQUIRE(resolver.get_resolved_macros().begin()->second == a_macro_pos);
REQUIRE(resolver.get_unknown_macros().size() == 1); REQUIRE(resolver.get_unknown_macros().size() == 1);
REQUIRE(resolver.get_unknown_macros().begin()->first == b_macro_name); REQUIRE(*resolver.get_unknown_macros().begin() == b_macro_name);
REQUIRE(resolver.get_unknown_macros().begin()->second == b_macro_pos);
REQUIRE(filter->is_equal(expected_filter.get())); REQUIRE(filter->is_equal(expected_filter.get()));
} }
} }
@@ -259,19 +214,15 @@ TEST_CASE("Should find unknown macros", "[rule_loader]")
TEST_CASE("Should undefine macro", "[rule_loader]") TEST_CASE("Should undefine macro", "[rule_loader]")
{ {
string macro_name = "test_macro"; string macro_name = "test_macro";
pos_info macro_pos_1 = create_pos(12, 9, 3);
pos_info macro_pos_2 = create_pos(9, 6, 3);
std::shared_ptr<expr> macro = std::move(unary_check_expr::create("test.field", "", "exists")); std::shared_ptr<expr> macro = std::move(unary_check_expr::create("test.field", "", "exists"));
std::shared_ptr<expr> a_filter = std::move(value_expr::create(macro_name, macro_pos_1)); std::shared_ptr<expr> a_filter = std::move(value_expr::create(macro_name));
std::shared_ptr<expr> b_filter = std::move(value_expr::create(macro_name, macro_pos_2)); std::shared_ptr<expr> b_filter = std::move(value_expr::create(macro_name));
filter_macro_resolver resolver; filter_macro_resolver resolver;
resolver.set_macro(macro_name, macro); resolver.set_macro(macro_name, macro);
REQUIRE(resolver.run(a_filter) == true); REQUIRE(resolver.run(a_filter) == true);
REQUIRE(resolver.get_resolved_macros().size() == 1); REQUIRE(resolver.get_resolved_macros().size() == 1);
REQUIRE(resolver.get_resolved_macros().begin()->first == macro_name); REQUIRE(*resolver.get_resolved_macros().begin() == macro_name);
REQUIRE(resolver.get_resolved_macros().begin()->second == macro_pos_1);
REQUIRE(resolver.get_unknown_macros().empty()); REQUIRE(resolver.get_unknown_macros().empty());
REQUIRE(a_filter->is_equal(macro.get())); REQUIRE(a_filter->is_equal(macro.get()));
@@ -279,24 +230,21 @@ TEST_CASE("Should undefine macro", "[rule_loader]")
REQUIRE(resolver.run(b_filter) == false); REQUIRE(resolver.run(b_filter) == false);
REQUIRE(resolver.get_resolved_macros().empty()); REQUIRE(resolver.get_resolved_macros().empty());
REQUIRE(resolver.get_unknown_macros().size() == 1); REQUIRE(resolver.get_unknown_macros().size() == 1);
REQUIRE(resolver.get_unknown_macros().begin()->first == macro_name); REQUIRE(*resolver.get_unknown_macros().begin() == macro_name);
REQUIRE(resolver.get_unknown_macros().begin()->second == macro_pos_2);
} }
// checks that the macro AST is cloned and not shared across resolved filters // checks that the macro AST is cloned and not shared across resolved filters
TEST_CASE("Should clone macro AST", "[rule_loader]") TEST_CASE("Should clone macro AST", "[rule_loader]")
{ {
string macro_name = "test_macro"; string macro_name = "test_macro";
pos_info macro_pos = create_pos(5, 2, 8888);
std::shared_ptr<unary_check_expr> macro = std::move(unary_check_expr::create("test.field", "", "exists")); std::shared_ptr<unary_check_expr> macro = std::move(unary_check_expr::create("test.field", "", "exists"));
std::shared_ptr<expr> filter = std::move(value_expr::create(macro_name, macro_pos)); std::shared_ptr<expr> filter = std::move(value_expr::create(macro_name));
filter_macro_resolver resolver; filter_macro_resolver resolver;
resolver.set_macro(macro_name, macro); resolver.set_macro(macro_name, macro);
REQUIRE(resolver.run(filter) == true); REQUIRE(resolver.run(filter) == true);
REQUIRE(resolver.get_resolved_macros().size() == 1); REQUIRE(resolver.get_resolved_macros().size() == 1);
REQUIRE(resolver.get_resolved_macros().begin()->first == macro_name); REQUIRE(*resolver.get_resolved_macros().begin() == macro_name);
REQUIRE(resolver.get_resolved_macros().begin()->second == macro_pos);
REQUIRE(resolver.get_unknown_macros().empty()); REQUIRE(resolver.get_unknown_macros().empty());
REQUIRE(filter->is_equal(macro.get())); REQUIRE(filter->is_equal(macro.get()));

View File

@@ -27,51 +27,30 @@ static uint16_t other_non_default_ruleset = 2;
static std::set<std::string> tags = {"some_tag", "some_other_tag"}; static std::set<std::string> tags = {"some_tag", "some_other_tag"};
static std::set<uint16_t> evttypes = { ppm_event_type::PPME_GENERIC_E }; static std::set<uint16_t> evttypes = { ppm_event_type::PPME_GENERIC_E };
static std::shared_ptr<gen_event_filter_factory> create_factory() static std::shared_ptr<libsinsp::filter::ast::expr> create_filter()
{
std::shared_ptr<gen_event_filter_factory> ret(new sinsp_filter_factory(NULL));
return ret;
}
static std::shared_ptr<libsinsp::filter::ast::expr> create_ast(
std::shared_ptr<gen_event_filter_factory> f)
{ {
libsinsp::filter::parser parser("evt.type=open"); libsinsp::filter::parser parser("evt.type=open");
std::shared_ptr<libsinsp::filter::ast::expr> ret(parser.parse()); std::shared_ptr<libsinsp::filter::ast::expr> ret(parser.parse());
return ret; return ret;
} }
static std::shared_ptr<gen_event_filter> create_filter( static std::shared_ptr<filter_ruleset> create_ruleset()
std::shared_ptr<gen_event_filter_factory> f,
std::shared_ptr<libsinsp::filter::ast::expr> ast)
{
sinsp_filter_compiler compiler(f, ast.get());
std::shared_ptr<gen_event_filter> filter(compiler.compile());
return filter;
}
static std::shared_ptr<filter_ruleset> create_ruleset(
std::shared_ptr<gen_event_filter_factory> f)
{ {
std::shared_ptr<gen_event_filter_factory> f(new sinsp_filter_factory(NULL));
std::shared_ptr<filter_ruleset> ret(new evttype_index_ruleset(f)); std::shared_ptr<filter_ruleset> ret(new evttype_index_ruleset(f));
return ret; return ret;
} }
TEST_CASE("Should enable/disable on ruleset", "[rulesets]") TEST_CASE("Should enable/disable on ruleset", "[rulesets]")
{ {
auto f = create_factory(); auto r = create_ruleset();
auto r = create_ruleset(f); auto filter = create_filter();
auto ast = create_ast(f);
auto filter = create_filter(f, ast);
falco_rule rule; falco_rule rule;
rule.name = "one_rule"; rule.name = "one_rule";
rule.source = falco_common::syscall_source; rule.source = falco_common::syscall_source;
rule.tags = tags; rule.tags = tags;
r->add(rule, filter, ast); r->add(rule, filter);
SECTION("Should enable/disable for exact match w/ default ruleset") SECTION("Should enable/disable for exact match w/ default ruleset")
{ {
@@ -205,23 +184,21 @@ TEST_CASE("Should enable/disable on ruleset", "[rulesets]")
TEST_CASE("Should enable/disable on ruleset for incremental adding tags", "[rulesets]") TEST_CASE("Should enable/disable on ruleset for incremental adding tags", "[rulesets]")
{ {
auto f = create_factory(); auto r = create_ruleset();
auto r = create_ruleset(f);
auto ast = create_ast(f);
auto rule1_filter = create_filter(f, ast); auto rule1_filter = create_filter();
falco_rule rule1; falco_rule rule1;
rule1.name = "one_rule"; rule1.name = "one_rule";
rule1.source = falco_common::syscall_source; rule1.source = falco_common::syscall_source;
rule1.tags = {"rule1_tag"}; rule1.tags = {"rule1_tag"};
r->add(rule1, rule1_filter, ast); r->add(rule1, rule1_filter);
auto rule2_filter = create_filter(f, ast); auto rule2_filter = create_filter();
falco_rule rule2; falco_rule rule2;
rule2.name = "two_rule"; rule2.name = "two_rule";
rule2.source = falco_common::syscall_source; rule2.source = falco_common::syscall_source;
rule2.tags = {"rule2_tag"}; rule2.tags = {"rule2_tag"};
r->add(rule2, rule2_filter, ast); r->add(rule2, rule2_filter);
std::set<std::string> want_tags; std::set<std::string> want_tags;

View File

@@ -28,6 +28,7 @@ set(FALCO_ENGINE_SOURCE_FILES
rule_loader_compiler.cpp) rule_loader_compiler.cpp)
add_library(falco_engine STATIC ${FALCO_ENGINE_SOURCE_FILES}) add_library(falco_engine STATIC ${FALCO_ENGINE_SOURCE_FILES})
add_dependencies(falco_engine njson string-view-lite)
if(USE_BUNDLED_DEPS) if(USE_BUNDLED_DEPS)
add_dependencies(falco_engine yamlcpp) add_dependencies(falco_engine yamlcpp)
@@ -39,6 +40,7 @@ if(MINIMAL_BUILD)
PUBLIC PUBLIC
"${NJSON_INCLUDE}" "${NJSON_INCLUDE}"
"${TBB_INCLUDE_DIR}" "${TBB_INCLUDE_DIR}"
"${STRING_VIEW_LITE_INCLUDE}"
"${LIBSCAP_INCLUDE_DIRS}" "${LIBSCAP_INCLUDE_DIRS}"
"${LIBSINSP_INCLUDE_DIRS}" "${LIBSINSP_INCLUDE_DIRS}"
"${YAMLCPP_INCLUDE_DIR}" "${YAMLCPP_INCLUDE_DIR}"
@@ -49,6 +51,7 @@ else()
PUBLIC PUBLIC
"${NJSON_INCLUDE}" "${NJSON_INCLUDE}"
"${TBB_INCLUDE_DIR}" "${TBB_INCLUDE_DIR}"
"${STRING_VIEW_LITE_INCLUDE}"
"${LIBSCAP_INCLUDE_DIRS}" "${LIBSCAP_INCLUDE_DIRS}"
"${LIBSINSP_INCLUDE_DIRS}" "${LIBSINSP_INCLUDE_DIRS}"
"${YAMLCPP_INCLUDE_DIR}" "${YAMLCPP_INCLUDE_DIR}"

View File

@@ -153,11 +153,12 @@ void evttype_index_ruleset::ruleset_filters::evttypes_for_ruleset(std::set<uint1
void evttype_index_ruleset::add( void evttype_index_ruleset::add(
const falco_rule& rule, const falco_rule& rule,
std::shared_ptr<gen_event_filter> filter,
std::shared_ptr<libsinsp::filter::ast::expr> condition) std::shared_ptr<libsinsp::filter::ast::expr> condition)
{ {
try try
{ {
sinsp_filter_compiler compiler(m_filter_factory, condition.get());
shared_ptr<gen_event_filter> filter(compiler.compile());
std::shared_ptr<filter_wrapper> wrap(new filter_wrapper()); std::shared_ptr<filter_wrapper> wrap(new filter_wrapper());
wrap->rule = rule; wrap->rule = rule;
wrap->filter = filter; wrap->filter = filter;

View File

@@ -41,7 +41,6 @@ public:
void add( void add(
const falco_rule& rule, const falco_rule& rule,
std::shared_ptr<gen_event_filter> filter,
std::shared_ptr<libsinsp::filter::ast::expr> condition) override; std::shared_ptr<libsinsp::filter::ast::expr> condition) override;
void clear() override; void clear() override;

View File

@@ -237,7 +237,7 @@ std::unique_ptr<load_result> falco_engine::load_rules_file(const string &rules_f
res->add_error(load_result::LOAD_ERR_FILE_READ, e.what(), ctx); res->add_error(load_result::LOAD_ERR_FILE_READ, e.what(), ctx);
return res; return std::move(res);
} }
return load_rules(rules_content, rules_filename); return load_rules(rules_content, rules_filename);

View File

@@ -31,14 +31,12 @@ struct falco_source
falco_source& operator = (falco_source&&) = default; falco_source& operator = (falco_source&&) = default;
falco_source(const falco_source& s): falco_source(const falco_source& s):
name(s.name), name(s.name),
ruleset(s.ruleset),
ruleset_factory(s.ruleset_factory), ruleset_factory(s.ruleset_factory),
filter_factory(s.filter_factory), filter_factory(s.filter_factory),
formatter_factory(s.formatter_factory) { }; formatter_factory(s.formatter_factory) { };
falco_source& operator = (const falco_source& s) falco_source& operator = (const falco_source& s)
{ {
name = s.name; name = s.name;
ruleset = s.ruleset;
ruleset_factory = s.ruleset_factory; ruleset_factory = s.ruleset_factory;
filter_factory = s.filter_factory; filter_factory = s.filter_factory;
formatter_factory = s.formatter_factory; formatter_factory = s.formatter_factory;

View File

@@ -20,7 +20,6 @@ limitations under the License.
#include <iomanip> #include <iomanip>
#include "falco_utils.h" #include "falco_utils.h"
#include "utils.h"
#include "banned.h" // This raises a compilation error when certain functions are used #include "banned.h" // This raises a compilation error when certain functions are used
namespace falco namespace falco
@@ -76,9 +75,9 @@ void readfile(const std::string& filename, std::string& data)
} }
namespace network namespace network
{ {
bool is_unix_scheme(const std::string& url) bool is_unix_scheme(nonstd::string_view url)
{ {
return sinsp_utils::startswith(url, UNIX_SCHEME); return url.starts_with(UNIX_SCHEME);
} }
} // namespace network } // namespace network
} // namespace utils } // namespace utils

View File

@@ -24,6 +24,7 @@ limitations under the License.
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <thread> #include <thread>
#include <nonstd/string_view.hpp>
#ifdef __GNUC__ #ifdef __GNUC__
#define likely(x) __builtin_expect(!!(x), 1) #define likely(x) __builtin_expect(!!(x), 1)
@@ -48,7 +49,7 @@ uint32_t hardware_concurrency();
namespace network namespace network
{ {
static const std::string UNIX_SCHEME("unix://"); static const std::string UNIX_SCHEME("unix://");
bool is_unix_scheme(const std::string& url); bool is_unix_scheme(nonstd::string_view url);
} // namespace network } // namespace network
} // namespace utils } // namespace utils
} // namespace falco } // namespace falco

View File

@@ -21,10 +21,12 @@ using namespace libsinsp::filter;
bool filter_macro_resolver::run(libsinsp::filter::ast::expr*& filter) bool filter_macro_resolver::run(libsinsp::filter::ast::expr*& filter)
{ {
visitor v;
m_unknown_macros.clear(); m_unknown_macros.clear();
m_resolved_macros.clear(); m_resolved_macros.clear();
v.m_unknown_macros = &m_unknown_macros;
visitor v(m_unknown_macros, m_resolved_macros, m_macros); v.m_resolved_macros = &m_resolved_macros;
v.m_macros = &m_macros;
v.m_node_substitute = nullptr; v.m_node_substitute = nullptr;
filter->accept(&v); filter->accept(&v);
if (v.m_node_substitute) if (v.m_node_substitute)
@@ -37,10 +39,12 @@ bool filter_macro_resolver::run(libsinsp::filter::ast::expr*& filter)
bool filter_macro_resolver::run(std::shared_ptr<libsinsp::filter::ast::expr>& filter) bool filter_macro_resolver::run(std::shared_ptr<libsinsp::filter::ast::expr>& filter)
{ {
visitor v;
m_unknown_macros.clear(); m_unknown_macros.clear();
m_resolved_macros.clear(); m_resolved_macros.clear();
v.m_unknown_macros = &m_unknown_macros;
visitor v(m_unknown_macros, m_resolved_macros, m_macros); v.m_resolved_macros = &m_resolved_macros;
v.m_macros = &m_macros;
v.m_node_substitute = nullptr; v.m_node_substitute = nullptr;
filter->accept(&v); filter->accept(&v);
if (v.m_node_substitute) if (v.m_node_substitute)
@@ -57,12 +61,12 @@ void filter_macro_resolver::set_macro(
m_macros[name] = macro; m_macros[name] = macro;
} }
const filter_macro_resolver::macro_info_map& filter_macro_resolver::get_unknown_macros() const const unordered_set<string>& filter_macro_resolver::get_unknown_macros() const
{ {
return m_unknown_macros; return m_unknown_macros;
} }
const filter_macro_resolver::macro_info_map& filter_macro_resolver::get_resolved_macros() const const unordered_set<string>& filter_macro_resolver::get_resolved_macros() const
{ {
return m_resolved_macros; return m_resolved_macros;
} }
@@ -125,8 +129,8 @@ void filter_macro_resolver::visitor::visit(ast::value_expr* e)
// we are supposed to get here only in case // we are supposed to get here only in case
// of identier-only children from either a 'not', // of identier-only children from either a 'not',
// an 'and' or an 'or'. // an 'and' or an 'or'.
auto macro = m_macros.find(e->value); auto macro = m_macros->find(e->value);
if (macro != m_macros.end() && macro->second) // skip null-ptr macros if (macro != m_macros->end() && macro->second) // skip null-ptr macros
{ {
m_node_substitute = nullptr; m_node_substitute = nullptr;
auto new_node = ast::clone(macro->second.get()); auto new_node = ast::clone(macro->second.get());
@@ -137,11 +141,11 @@ void filter_macro_resolver::visitor::visit(ast::value_expr* e)
{ {
m_node_substitute = std::move(new_node); m_node_substitute = std::move(new_node);
} }
m_resolved_macros[e->value] = e->get_pos(); m_resolved_macros->insert(e->value);
} }
else else
{ {
m_node_substitute = nullptr; m_node_substitute = nullptr;
m_unknown_macros[e->value] = e->get_pos(); m_unknown_macros->insert(e->value);
} }
} }

View File

@@ -40,7 +40,7 @@ class filter_macro_resolver
\return true if at least one of the defined macros is resolved \return true if at least one of the defined macros is resolved
*/ */
bool run(libsinsp::filter::ast::expr*& filter); bool run(libsinsp::filter::ast::expr*& filter);
/*! /*!
\brief Version of run() that works with shared pointers \brief Version of run() that works with shared pointers
*/ */
@@ -58,17 +58,12 @@ class filter_macro_resolver
std::string name, std::string name,
std::shared_ptr<libsinsp::filter::ast::expr> macro); std::shared_ptr<libsinsp::filter::ast::expr> macro);
/*!
\brief used in get_{resolved,unknown}_macros
*/
typedef std::unordered_map<std::string,libsinsp::filter::ast::pos_info> macro_info_map;
/*! /*!
\brief Returns a set containing the names of all the macros \brief Returns a set containing the names of all the macros
substituted during the last invocation of run(). Should be substituted during the last invocation of run(). Should be
non-empty if the last invocation of run() returned true. non-empty if the last invocation of run() returned true.
*/ */
const macro_info_map& get_resolved_macros() const; const std::unordered_set<std::string>& get_resolved_macros() const;
/*! /*!
\brief Returns a set containing the names of all the macros \brief Returns a set containing the names of all the macros
@@ -76,8 +71,8 @@ class filter_macro_resolver
A macro remains unresolved if it is found inside the processed A macro remains unresolved if it is found inside the processed
filter but it was not defined with set_macro(); filter but it was not defined with set_macro();
*/ */
const macro_info_map& get_unknown_macros() const; const std::unordered_set<std::string>& get_unknown_macros() const;
private: private:
typedef std::unordered_map< typedef std::unordered_map<
std::string, std::string,
@@ -86,18 +81,16 @@ class filter_macro_resolver
struct visitor : public libsinsp::filter::ast::expr_visitor struct visitor : public libsinsp::filter::ast::expr_visitor
{ {
visitor(macro_info_map& unknown_macros, macro_info_map& resolved_macros, macro_defs& macros) visitor() = default;
: m_unknown_macros(unknown_macros), m_resolved_macros(resolved_macros), m_macros(macros) {}
visitor(visitor&&) = default; visitor(visitor&&) = default;
visitor& operator = (visitor&&) = default; visitor& operator = (visitor&&) = default;
visitor(const visitor&) = delete; visitor(const visitor&) = delete;
visitor& operator = (const visitor&) = delete; visitor& operator = (const visitor&) = delete;
std::unique_ptr<libsinsp::filter::ast::expr> m_node_substitute; std::unique_ptr<libsinsp::filter::ast::expr> m_node_substitute;
macro_info_map& m_unknown_macros; std::unordered_set<std::string>* m_unknown_macros;
macro_info_map& m_resolved_macros; std::unordered_set<std::string>* m_resolved_macros;
macro_defs* m_macros;
macro_defs& m_macros;
void visit(libsinsp::filter::ast::and_expr* e) override; void visit(libsinsp::filter::ast::and_expr* e) override;
void visit(libsinsp::filter::ast::or_expr* e) override; void visit(libsinsp::filter::ast::or_expr* e) override;
@@ -108,7 +101,7 @@ class filter_macro_resolver
void visit(libsinsp::filter::ast::binary_check_expr* e) override; void visit(libsinsp::filter::ast::binary_check_expr* e) override;
}; };
macro_info_map m_unknown_macros; std::unordered_set<std::string> m_unknown_macros;
macro_info_map m_resolved_macros; std::unordered_set<std::string> m_resolved_macros;
macro_defs m_macros; macro_defs m_macros;
}; };

View File

@@ -32,20 +32,16 @@ public:
virtual ~filter_ruleset() = default; virtual ~filter_ruleset() = default;
/*! /*!
\brief Adds a rule and its filtering filter + condition inside the manager. \brief Adds a rule and its filtering condition inside the manager.
This method only adds the rule inside the internal collection, An exception is thrown is case of error. This method only adds the rule
but does not enable it for any ruleset. The rule must be enabled inside the internal collection, but does not enable it for any ruleset.
for one or more rulesets with the enable() or enable_tags() methods. The rule must be enabled for one or more rulesets with the enable() or
The ast representation of the rule's condition is provided to allow enable_tags() methods.
the filter_ruleset object to parse the ast to obtain event types
or do other analysis/indexing of the condition.
\param rule The rule to be added \param rule The rule to be added
\param the filter representing the rule's filtering condition.
\param condition The AST representing the rule's filtering condition \param condition The AST representing the rule's filtering condition
*/ */
virtual void add( virtual void add(
const falco_rule& rule, const falco_rule& rule,
std::shared_ptr<gen_event_filter> filter,
std::shared_ptr<libsinsp::filter::ast::expr> condition) = 0; std::shared_ptr<libsinsp::filter::ast::expr> condition) = 0;
/*! /*!

View File

@@ -234,7 +234,6 @@ static bool resolve_list(std::string& cnd, const rule_loader::list_info& list)
static void resolve_macros( static void resolve_macros(
indexed_vector<rule_loader::macro_info>& macros, indexed_vector<rule_loader::macro_info>& macros,
std::shared_ptr<ast::expr>& ast, std::shared_ptr<ast::expr>& ast,
const std::string& condition,
uint32_t visibility, uint32_t visibility,
const rule_loader::context &ctx) const rule_loader::context &ctx)
{ {
@@ -249,22 +248,15 @@ static void resolve_macros(
macro_resolver.run(ast); macro_resolver.run(ast);
// Note: only complaining about the first unknown macro // Note: only complaining about the first unknown macro
const filter_macro_resolver::macro_info_map& unresolved_macros = macro_resolver.get_unknown_macros(); THROW(!macro_resolver.get_unknown_macros().empty(),
if(!unresolved_macros.empty()) std::string("Undefined macro '")
{ + *macro_resolver.get_unknown_macros().begin()
auto it = unresolved_macros.begin(); + "' used in filter.",
const rule_loader::context cond_ctx(it->second, condition, ctx); ctx);
THROW(true, for (auto &m : macro_resolver.get_resolved_macros())
std::string("Undefined macro '")
+ it->first
+ "' used in filter.",
cond_ctx);
}
for (auto &it : macro_resolver.get_resolved_macros())
{ {
macros.at(it.first)->used = true; macros.at(m)->used = true;
} }
} }
@@ -371,7 +363,7 @@ void rule_loader::compiler::compile_macros_infos(
for (auto &m : out) for (auto &m : out)
{ {
resolve_macros(out, m.cond_ast, m.cond, m.visibility, m.ctx); resolve_macros(out, m.cond_ast, m.visibility, m.ctx);
} }
} }
@@ -412,7 +404,7 @@ void rule_loader::compiler::compile_rule_infos(
r.exceptions, rule.exception_fields, condition); r.exceptions, rule.exception_fields, condition);
} }
auto ast = parse_condition(condition, lists, r.cond_ctx); auto ast = parse_condition(condition, lists, r.cond_ctx);
resolve_macros(macros, ast, condition, MAX_VISIBILITY, r.ctx); resolve_macros(macros, ast, MAX_VISIBILITY, r.ctx);
// check for warnings in the filtering condition // check for warnings in the filtering condition
warn_codes.clear(); warn_codes.clear();
@@ -452,12 +444,10 @@ void rule_loader::compiler::compile_rule_infos(
// This also compiles the filter, and might throw a // This also compiles the filter, and might throw a
// falco_exception with details on the compilation // falco_exception with details on the compilation
// failure. // failure.
sinsp_filter_compiler compiler(cfg.sources.at(r.source)->filter_factory, ast.get());
try { try {
shared_ptr<gen_event_filter> filter(compiler.compile()); source->ruleset->add(*out.at(rule_id), ast);
source->ruleset->add(*out.at(rule_id), filter, ast);
} }
catch (const sinsp_exception& e) catch (const falco_exception& e)
{ {
// Allow errors containing "nonexistent field" if // Allow errors containing "nonexistent field" if
// skip_if_unknown_filter is true // skip_if_unknown_filter is true
@@ -473,14 +463,10 @@ void rule_loader::compiler::compile_rule_infos(
} }
else else
{ {
rule_loader::context ctx(compiler.get_pos(),
condition,
r.cond_ctx);
throw rule_loader::rule_load_exception( throw rule_loader::rule_load_exception(
falco::load_result::load_result::LOAD_ERR_COMPILE_CONDITION, falco::load_result::load_result::LOAD_ERR_COMPILE_CONDITION,
e.what(), e.what(),
ctx); r.cond_ctx);
} }
} }

View File

@@ -62,6 +62,7 @@ set(
"${PROJECT_SOURCE_DIR}/userspace/engine" "${PROJECT_SOURCE_DIR}/userspace/engine"
"${PROJECT_BINARY_DIR}/userspace/falco" "${PROJECT_BINARY_DIR}/userspace/falco"
"${PROJECT_BINARY_DIR}/driver/src" "${PROJECT_BINARY_DIR}/driver/src"
"${STRING_VIEW_LITE_INCLUDE}"
"${CXXOPTS_INCLUDE_DIR}" "${CXXOPTS_INCLUDE_DIR}"
"${YAMLCPP_INCLUDE_DIR}" "${YAMLCPP_INCLUDE_DIR}"
"${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}"
@@ -72,6 +73,7 @@ list(APPEND FALCO_INCLUDE_DIRECTORIES "${FALCO_EXTRA_INCLUDE_DIRS}")
set( set(
FALCO_DEPENDENCIES FALCO_DEPENDENCIES
string-view-lite
b64 b64
cxxopts cxxopts
) )

View File

@@ -28,7 +28,7 @@ application::run_result application::configure_syscall_buffer_size()
/* We don't need to compute the syscall buffer dimension if we are in capture mode or if the /* We don't need to compute the syscall buffer dimension if we are in capture mode or if the
* the syscall source is not enabled. * the syscall source is not enabled.
*/ */
if(is_capture_mode() || m_state->enabled_sources.find(falco_common::syscall_source) == m_state->enabled_sources.end() || is_gvisor_enabled()) if(is_capture_mode() || m_state->enabled_sources.find(falco_common::syscall_source) == m_state->enabled_sources.end())
{ {
return run_result::ok(); return run_result::ok();
} }

View File

@@ -29,21 +29,11 @@ void application::configure_output_format()
output_format = "container=%container.name (id=%container.id)"; output_format = "container=%container.name (id=%container.id)";
replace_container_info = true; replace_container_info = true;
} }
else if(m_options.print_additional == "cg" || m_options.print_additional == "container-gvisor")
{
output_format = "container=%container.name (id=%container.id) vpid=%proc.vpid vtid=%thread.vtid";
replace_container_info = true;
}
else if(m_options.print_additional == "k" || m_options.print_additional == "kubernetes") else if(m_options.print_additional == "k" || m_options.print_additional == "kubernetes")
{ {
output_format = "k8s.ns=%k8s.ns.name k8s.pod=%k8s.pod.name container=%container.id"; output_format = "k8s.ns=%k8s.ns.name k8s.pod=%k8s.pod.name container=%container.id";
replace_container_info = true; replace_container_info = true;
} }
else if(m_options.print_additional == "kg" || m_options.print_additional == "kubernetes-gvisor")
{
output_format = "k8s.ns=%k8s.ns.name k8s.pod=%k8s.pod.name container=%container.id vpid=%proc.vpid vtid=%thread.vtid";
replace_container_info = true;
}
else if(m_options.print_additional == "m" || m_options.print_additional == "mesos") else if(m_options.print_additional == "m" || m_options.print_additional == "mesos")
{ {
output_format = "task=%mesos.task.name container=%container.id"; output_format = "task=%mesos.task.name container=%container.id";
@@ -54,6 +44,11 @@ void application::configure_output_format()
output_format = m_options.print_additional; output_format = m_options.print_additional;
replace_container_info = false; replace_container_info = false;
} }
else if(m_options.gvisor_config != "")
{
output_format = "container=%container.name (id=%container.id) vpid=%proc.vpid vtid=%thread.vtid";
replace_container_info = true;
}
if(!output_format.empty()) if(!output_format.empty())
{ {

View File

@@ -16,6 +16,8 @@ limitations under the License.
#pragma once #pragma once
#define FALCO_BRANCH "@FALCO_REF@"
#define FALCO_HASH "@FALCO_HASH@"
#define FALCO_VERSION "@FALCO_VERSION@" #define FALCO_VERSION "@FALCO_VERSION@"
#define FALCO_VERSION_MAJOR @FALCO_VERSION_MAJOR@ #define FALCO_VERSION_MAJOR @FALCO_VERSION_MAJOR@
#define FALCO_VERSION_MINOR @FALCO_VERSION_MINOR@ #define FALCO_VERSION_MINOR @FALCO_VERSION_MINOR@

View File

@@ -4,7 +4,7 @@ set -euo pipefail
SOURCE_DIR=$1 SOURCE_DIR=$1
NEW_CHECKSUM=$(./falco -c ${SOURCE_DIR}/falco.yaml --list=syscall -N | sha256sum | awk '{print $1}') NEW_CHECKSUM=$(./falco -c ${SOURCE_DIR}/falco.yaml --list -N | sha256sum | awk '{print $1}')
CUR_CHECKSUM=$(grep FALCO_FIELDS_CHECKSUM "${SOURCE_DIR}/userspace/engine/falco_engine_version.h" | awk '{print $3}' | sed -e 's/"//g') CUR_CHECKSUM=$(grep FALCO_FIELDS_CHECKSUM "${SOURCE_DIR}/userspace/engine/falco_engine_version.h" | awk '{print $3}' | sed -e 's/"//g')
if [ "$NEW_CHECKSUM" != "$CUR_CHECKSUM" ]; then if [ "$NEW_CHECKSUM" != "$CUR_CHECKSUM" ]; then

View File

@@ -16,7 +16,6 @@ limitations under the License.
#pragma once #pragma once
#define CPPHTTPLIB_OPENSSL_SUPPORT #define CPPHTTPLIB_OPENSSL_SUPPORT
#define CPPHTTPLIB_ZLIB_SUPPORT
#include <httplib.h> #include <httplib.h>
#include <thread> #include <thread>
#include "configuration.h" #include "configuration.h"