mirror of
https://github.com/falcosecurity/falco.git
synced 2026-03-20 19:52:08 +00:00
Compare commits
5 Commits
build/docs
...
fix/1272
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ab327749f | ||
|
|
4450fd3c4c | ||
|
|
5cca1a6589 | ||
|
|
130126f170 | ||
|
|
c886debf83 |
@@ -1,85 +1,5 @@
|
||||
version: 2
|
||||
jobs:
|
||||
# Build a statically linked Falco release binary using musl
|
||||
# This build is 100% static, there are no host dependencies
|
||||
"build/musl":
|
||||
docker:
|
||||
- image: alpine:3.12
|
||||
steps:
|
||||
- checkout:
|
||||
path: /source-static/falco
|
||||
- run:
|
||||
name: Update base image
|
||||
command: apk update
|
||||
- run:
|
||||
name: Install build dependencies
|
||||
command: apk add g++ gcc cmake cmake make ncurses-dev git bash perl linux-headers autoconf automake m4 libtool elfutils-dev libelf-static patch binutils
|
||||
- run:
|
||||
name: Prepare project
|
||||
command: |
|
||||
mkdir -p /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 -DMUSL_OPTIMIZED_BUILD=On -DFALCO_ETC_DIR=/etc/falco /source-static/falco
|
||||
- run:
|
||||
name: Build
|
||||
command: |
|
||||
cd /build-static/release
|
||||
make -j4 all
|
||||
- run:
|
||||
name: Package
|
||||
command: |
|
||||
cd /build-static/release
|
||||
make -j4 package
|
||||
- run:
|
||||
name: Run unit tests
|
||||
command: |
|
||||
cd /build-static/release
|
||||
make tests
|
||||
- run:
|
||||
name: Prepare artifacts
|
||||
command: |
|
||||
mkdir -p /tmp/packages
|
||||
cp /build-static/release/*.tar.gz /tmp/packages
|
||||
- store_artifacts:
|
||||
path: /tmp/packages
|
||||
destination: /packages
|
||||
- persist_to_workspace:
|
||||
root: /
|
||||
paths:
|
||||
- build-static/release
|
||||
- source-static
|
||||
# Build the minimal Falco
|
||||
# This build only contains the Falco engine and the basic input/output.
|
||||
"build/minimal":
|
||||
docker:
|
||||
- image: ubuntu:focal
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Update base image
|
||||
command: apt update -y
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: DEBIAN_FRONTEND=noninteractive apt install libjq-dev libncurses-dev libyaml-cpp-dev libelf-dev cmake build-essential git -y
|
||||
- run:
|
||||
name: Prepare project
|
||||
command: |
|
||||
mkdir build-minimal
|
||||
pushd build-minimal
|
||||
cmake -DMINIMAL_BUILD=On -DBUILD_BPF=Off -DBUILD_DRIVER=Off -DCMAKE_BUILD_TYPE=Release ..
|
||||
popd
|
||||
- run:
|
||||
name: Build
|
||||
command: |
|
||||
pushd build-minimal
|
||||
make -j4 all
|
||||
popd
|
||||
- run:
|
||||
name: Run unit tests
|
||||
command: |
|
||||
pushd build-minimal
|
||||
make tests
|
||||
popd
|
||||
# Build using ubuntu LTS
|
||||
# This build is dynamic, most dependencies are taken from the OS
|
||||
"build/ubuntu-focal":
|
||||
@@ -144,72 +64,8 @@ jobs:
|
||||
pushd build
|
||||
make tests
|
||||
popd
|
||||
# Build using Ubuntu Bionic Beaver (18.04)
|
||||
# This build is static, dependencies are bundled in the Falco binary
|
||||
"build/ubuntu-bionic":
|
||||
docker:
|
||||
- image: ubuntu:bionic
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Update base image
|
||||
command: apt update -y
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: DEBIAN_FRONTEND=noninteractive apt install cmake build-essential clang llvm git linux-headers-generic libncurses-dev pkg-config autoconf libtool libelf-dev -y
|
||||
- run:
|
||||
name: Prepare project
|
||||
command: |
|
||||
mkdir build
|
||||
pushd build
|
||||
cmake -DBUILD_BPF=On -DUSE_BUNDLED_DEPS=On ..
|
||||
popd
|
||||
- run:
|
||||
name: Build
|
||||
command: |
|
||||
pushd build
|
||||
KERNELDIR=/lib/modules/$(ls /lib/modules)/build make -j4 all
|
||||
popd
|
||||
- run:
|
||||
name: Run unit tests
|
||||
command: |
|
||||
pushd build
|
||||
make tests
|
||||
popd
|
||||
# Build using CentOS 8
|
||||
# This build is static, dependencies are bundled in the Falco binary
|
||||
"build/centos8":
|
||||
docker:
|
||||
- image: centos:8
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Update base image
|
||||
command: dnf update -y
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: dnf install gcc gcc-c++ git make cmake autoconf automake pkg-config patch ncurses-devel libtool elfutils-libelf-devel diffutils kernel-devel kernel-headers kernel-core clang llvm which -y
|
||||
- run:
|
||||
name: Prepare project
|
||||
command: |
|
||||
mkdir build
|
||||
pushd build
|
||||
cmake -DBUILD_BPF=On -DUSE_BUNDLED_DEPS=On ..
|
||||
popd
|
||||
- run:
|
||||
name: Build
|
||||
command: |
|
||||
pushd build
|
||||
KERNELDIR=/lib/modules/$(ls /lib/modules)/build make -j4 all
|
||||
popd
|
||||
- run:
|
||||
name: Run unit tests
|
||||
command: |
|
||||
pushd build
|
||||
make tests
|
||||
popd
|
||||
# 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":
|
||||
docker:
|
||||
- image: falcosecurity/falco-builder:latest
|
||||
@@ -246,7 +102,7 @@ jobs:
|
||||
path: /tmp/packages
|
||||
destination: /packages
|
||||
# Debug 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-debug":
|
||||
docker:
|
||||
- image: falcosecurity/falco-builder:latest
|
||||
@@ -282,25 +138,6 @@ jobs:
|
||||
- run:
|
||||
name: Execute integration tests
|
||||
command: /usr/bin/entrypoint test
|
||||
- store_test_results:
|
||||
path: /build/release/integration-tests-xunit
|
||||
"tests/integration-static":
|
||||
docker:
|
||||
- image: falcosecurity/falco-tester:latest
|
||||
environment:
|
||||
SOURCE_DIR: "/source-static"
|
||||
BUILD_DIR: "/build-static"
|
||||
BUILD_TYPE: "release"
|
||||
SKIP_PACKAGES_TESTS: "true"
|
||||
steps:
|
||||
- setup_remote_docker
|
||||
- attach_workspace:
|
||||
at: /
|
||||
- run:
|
||||
name: Execute integration tests
|
||||
command: /usr/bin/entrypoint test
|
||||
- store_test_results:
|
||||
path: /build-static/release/integration-tests-xunit
|
||||
"tests/driver-loader/integration":
|
||||
machine:
|
||||
image: ubuntu-1604:202004-01
|
||||
@@ -310,33 +147,6 @@ jobs:
|
||||
- run:
|
||||
name: Execute driver-loader integration tests
|
||||
command: /tmp/ws/source/falco/test/driver-loader/run_test.sh /tmp/ws/build/release/
|
||||
# Code quality
|
||||
"quality/static-analysis":
|
||||
docker:
|
||||
- image: falcosecurity/falco-builder:latest
|
||||
environment:
|
||||
BUILD_TYPE: "release"
|
||||
steps:
|
||||
- run:
|
||||
name: Install cppcheck
|
||||
command: |
|
||||
yum update -y
|
||||
yum install epel-release -y
|
||||
yum install cppcheck cppcheck-htmlreport -y
|
||||
- checkout:
|
||||
path: /source/falco
|
||||
- run:
|
||||
name: Prepare project
|
||||
command: /usr/bin/entrypoint cmake
|
||||
- run:
|
||||
name: cppcheck
|
||||
command: /usr/bin/entrypoint cppcheck
|
||||
- run:
|
||||
name: cppcheck html report
|
||||
command: /usr/bin/entrypoint cppcheck_htmlreport
|
||||
- store_artifacts:
|
||||
path: /build/release/static-analysis-reports
|
||||
destination: /static-analysis-reports
|
||||
# Sign rpm packages
|
||||
"rpm/sign":
|
||||
docker:
|
||||
@@ -393,34 +203,10 @@ jobs:
|
||||
FALCO_VERSION=$(cat /build/release/userspace/falco/config_falco.h | grep 'FALCO_VERSION ' | cut -d' ' -f3 | sed -e 's/^"//' -e 's/"$//')
|
||||
jfrog bt u /build/release/falco-${FALCO_VERSION}-x86_64.rpm falcosecurity/rpm-dev/falco/${FALCO_VERSION} --user poiana --key ${BINTRAY_SECRET} --publish --override
|
||||
- run:
|
||||
name: Publish bin-dev
|
||||
name: Publish tgz-dev
|
||||
command: |
|
||||
FALCO_VERSION=$(cat /build-static/release/userspace/falco/config_falco.h | grep 'FALCO_VERSION ' | cut -d' ' -f3 | sed -e 's/^"//' -e 's/"$//')
|
||||
jfrog bt u /build-static/release/falco-${FALCO_VERSION}-x86_64.tar.gz falcosecurity/bin-dev/falco/${FALCO_VERSION} x86_64/ --user poiana --key ${BINTRAY_SECRET} --publish --override
|
||||
# Clenup the Falco development release packages
|
||||
"cleanup/packages-dev":
|
||||
docker:
|
||||
- image: docker.bintray.io/jfrog/jfrog-cli-go:latest
|
||||
steps:
|
||||
- checkout:
|
||||
path: /source/falco
|
||||
- run:
|
||||
name: Prepare env
|
||||
command: |
|
||||
apk add --no-cache --update
|
||||
apk add curl jq
|
||||
- run:
|
||||
name: Only keep the 10 most recent Falco development release tarballs
|
||||
command: |
|
||||
/source/falco/scripts/cleanup -p ${BINTRAY_SECRET} -r bin-dev
|
||||
- run:
|
||||
name: Only keep the 50 most recent Falco development release RPMs
|
||||
command: |
|
||||
/source/falco/scripts/cleanup -p ${BINTRAY_SECRET} -r rpm-dev
|
||||
- run:
|
||||
name: Only keep the 50 most recent Falco development release DEBs
|
||||
command: |
|
||||
/source/falco/scripts/cleanup -p ${BINTRAY_SECRET} -r deb-dev
|
||||
FALCO_VERSION=$(cat /build/release/userspace/falco/config_falco.h | grep 'FALCO_VERSION ' | cut -d' ' -f3 | sed -e 's/^"//' -e 's/"$//')
|
||||
jfrog bt u /build/release/falco-${FALCO_VERSION}-x86_64.tar.gz falcosecurity/bin-dev/falco/${FALCO_VERSION} x86_64/ --user poiana --key ${BINTRAY_SECRET} --publish --override
|
||||
# Publish docker packages
|
||||
"publish/docker-dev":
|
||||
docker:
|
||||
@@ -477,10 +263,10 @@ jobs:
|
||||
FALCO_VERSION=$(cat /build/release/userspace/falco/config_falco.h | grep 'FALCO_VERSION ' | cut -d' ' -f3 | sed -e 's/^"//' -e 's/"$//')
|
||||
jfrog bt u /build/release/falco-${FALCO_VERSION}-x86_64.rpm falcosecurity/rpm/falco/${FALCO_VERSION} --user poiana --key ${BINTRAY_SECRET} --publish --override
|
||||
- run:
|
||||
name: Publish bin
|
||||
name: Publish tgz
|
||||
command: |
|
||||
FALCO_VERSION=$(cat /build-static/release/userspace/falco/config_falco.h | grep 'FALCO_VERSION ' | cut -d' ' -f3 | sed -e 's/^"//' -e 's/"$//')
|
||||
jfrog bt u /build-static/release/falco-${FALCO_VERSION}-x86_64.tar.gz falcosecurity/bin/falco/${FALCO_VERSION} x86_64/ --user poiana --key ${BINTRAY_SECRET} --publish --override
|
||||
FALCO_VERSION=$(cat /build/release/userspace/falco/config_falco.h | grep 'FALCO_VERSION ' | cut -d' ' -f3 | sed -e 's/^"//' -e 's/"$//')
|
||||
jfrog bt u /build/release/falco-${FALCO_VERSION}-x86_64.tar.gz falcosecurity/bin/falco/${FALCO_VERSION} x86_64/ --user poiana --key ${BINTRAY_SECRET} --publish --override
|
||||
# Publish docker packages
|
||||
"publish/docker":
|
||||
docker:
|
||||
@@ -522,20 +308,13 @@ workflows:
|
||||
version: 2
|
||||
build_and_test:
|
||||
jobs:
|
||||
- "build/musl"
|
||||
- "build/minimal"
|
||||
- "build/ubuntu-focal"
|
||||
- "build/ubuntu-focal-debug"
|
||||
- "build/ubuntu-bionic"
|
||||
- "build/centos8"
|
||||
- "build/centos7"
|
||||
- "build/centos7-debug"
|
||||
- "tests/integration":
|
||||
requires:
|
||||
- "build/centos7"
|
||||
- "tests/integration-static":
|
||||
requires:
|
||||
- "build/musl"
|
||||
- "tests/driver-loader/integration":
|
||||
requires:
|
||||
- "build/centos7"
|
||||
@@ -557,16 +336,6 @@ workflows:
|
||||
only: master
|
||||
requires:
|
||||
- "rpm/sign"
|
||||
- "tests/integration-static"
|
||||
- "cleanup/packages-dev":
|
||||
context: falco
|
||||
filters:
|
||||
tags:
|
||||
ignore: /.*/
|
||||
branches:
|
||||
only: master
|
||||
requires:
|
||||
- "publish/packages-dev"
|
||||
- "publish/docker-dev":
|
||||
context: falco
|
||||
filters:
|
||||
@@ -577,15 +346,8 @@ workflows:
|
||||
requires:
|
||||
- "publish/packages-dev"
|
||||
- "tests/driver-loader/integration"
|
||||
- "quality/static-analysis"
|
||||
release:
|
||||
jobs:
|
||||
- "build/musl":
|
||||
filters:
|
||||
tags:
|
||||
only: /.*/
|
||||
branches:
|
||||
ignore: /.*/
|
||||
- "build/centos7":
|
||||
filters:
|
||||
tags:
|
||||
@@ -604,7 +366,6 @@ workflows:
|
||||
- "publish/packages":
|
||||
context: falco
|
||||
requires:
|
||||
- "build/musl"
|
||||
- "rpm/sign"
|
||||
filters:
|
||||
tags:
|
||||
|
||||
20
.github/stale.yml
vendored
Normal file
20
.github/stale.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 60
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 7
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- cncf
|
||||
- roadmap
|
||||
- "help wanted"
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: wontfix
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
Issues labeled "cncf", "roadmap" and "help wanted" will not be automatically closed.
|
||||
Please refer to a maintainer to get such label added if you think this should be kept open.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: false
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -11,6 +11,8 @@ test/.phoronix-test-suite
|
||||
test/results*.json.*
|
||||
test/build
|
||||
|
||||
userspace/falco/lua/re.lua
|
||||
userspace/falco/lua/lpeg.so
|
||||
userspace/engine/lua/lyaml
|
||||
userspace/engine/lua/lyaml.lua
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
std = "min"
|
||||
cache = true
|
||||
include_files = {
|
||||
"userspace/falco/lua/*.lua",
|
||||
"userspace/engine/lua/*.lua",
|
||||
"userspace/engine/lua/lyaml/*.lua",
|
||||
"*.luacheckrc"
|
||||
|
||||
97
CHANGELOG.md
97
CHANGELOG.md
@@ -1,101 +1,6 @@
|
||||
# Change Log
|
||||
|
||||
## v0.26.2
|
||||
|
||||
Released on 2020-11-10
|
||||
|
||||
### Major Changes
|
||||
|
||||
* update: DRIVERS_REPO now defaults to https://download.falco.org/driver [[#1460](https://github.com/falcosecurity/falco/pull/1460)] - [@leodido](https://github.com/leodido)
|
||||
|
||||
## v0.26.1
|
||||
|
||||
Released on 2020-10-01
|
||||
|
||||
### Major Changes
|
||||
|
||||
* new: CLI flag `--alternate-lua-dir` to load Lua files from arbitrary paths [[#1419](https://github.com/falcosecurity/falco/pull/1419)] - [@admiral0](https://github.com/admiral0)
|
||||
|
||||
|
||||
### Rule Changes
|
||||
|
||||
* rule(Delete or rename shell history): fix warnings/FPs + container teardown [[#1423](https://github.com/falcosecurity/falco/pull/1423)] - [@mstemm](https://github.com/mstemm)
|
||||
* rule(Write below root): ensure proc_name_exists too [[#1423](https://github.com/falcosecurity/falco/pull/1423)] - [@mstemm](https://github.com/mstemm)
|
||||
|
||||
|
||||
## v0.26.0
|
||||
|
||||
Released on 2020-24-09
|
||||
|
||||
### Major Changes
|
||||
|
||||
* new: address several sources of FPs, primarily from GKE environments. [[#1372](https://github.com/falcosecurity/falco/pull/1372)] - [@mstemm](https://github.com/mstemm)
|
||||
* new: driver updated to 2aa88dcf6243982697811df4c1b484bcbe9488a2 [[#1410](https://github.com/falcosecurity/falco/pull/1410)] - [@leogr](https://github.com/leogr)
|
||||
* new(scripts/falco-driver-loader): detect and try to build the Falco kernel module driver using different GCC versions available in the current environment. [[#1408](https://github.com/falcosecurity/falco/pull/1408)] - [@fntlnz](https://github.com/fntlnz)
|
||||
* new: tgz (tarball) containing the statically-linked (musl) binary of Falco is now automatically built and published on bintray [[#1377](https://github.com/falcosecurity/falco/pull/1377)] - [@leogr](https://github.com/leogr)
|
||||
|
||||
|
||||
### Minor Changes
|
||||
|
||||
* update: bump Falco engine version to 7 [[#1381](https://github.com/falcosecurity/falco/pull/1381)] - [@leogr](https://github.com/leogr)
|
||||
* update: the required_engine_version is now on by default [[#1381](https://github.com/falcosecurity/falco/pull/1381)] - [@leogr](https://github.com/leogr)
|
||||
* update: falcosecurity/falco-no-driver image now uses the statically-linked Falco [[#1377](https://github.com/falcosecurity/falco/pull/1377)] - [@leogr](https://github.com/leogr)
|
||||
* docs(proposals): artifacts storage [[#1375](https://github.com/falcosecurity/falco/pull/1375)] - [@leodido](https://github.com/leodido)
|
||||
* docs(proposals): artifacts cleanup [[#1375](https://github.com/falcosecurity/falco/pull/1375)] - [@leodido](https://github.com/leodido)
|
||||
|
||||
|
||||
### Rule Changes
|
||||
|
||||
* rule(macro inbound_outbound): add brackets to disambiguate operator precedence [[#1373](https://github.com/falcosecurity/falco/pull/1373)] - [@ldegio](https://github.com/ldegio)
|
||||
* rule(macro redis_writing_conf): add brackets to disambiguate operator precedence [[#1373](https://github.com/falcosecurity/falco/pull/1373)] - [@ldegio](https://github.com/ldegio)
|
||||
* rule(macro run_by_foreman): add brackets to disambiguate operator precedence [[#1373](https://github.com/falcosecurity/falco/pull/1373)] - [@ldegio](https://github.com/ldegio)
|
||||
* rule(macro consider_packet_socket_communication): enable "Packet socket created in container" rule by default. [[#1402](https://github.com/falcosecurity/falco/pull/1402)] - [@rung](https://github.com/rung)
|
||||
* rule(Delete or rename shell history): skip docker overlay filesystems when considering bash history [[#1393](https://github.com/falcosecurity/falco/pull/1393)] - [@mstemm](https://github.com/mstemm)
|
||||
* rule(Disallowed K8s User): quote colons in user names [[#1393](https://github.com/falcosecurity/falco/pull/1393)] - [@mstemm](https://github.com/mstemm)
|
||||
* rule(macro falco_sensitive_mount_containers): Adds a trailing slash to avoid repo naming issues [[#1394](https://github.com/falcosecurity/falco/pull/1394)] - [@bgeesaman](https://github.com/bgeesaman)
|
||||
* rule: adds user.loginuid to the default Falco rules that also contain user.name [[#1369](https://github.com/falcosecurity/falco/pull/1369)] - [@csschwe](https://github.com/csschwe)
|
||||
|
||||
## v0.25.0
|
||||
|
||||
Released on 2020-08-25
|
||||
|
||||
### Major Changes
|
||||
|
||||
* new(userspace/falco): print the Falco and driver versions at the very beginning of the output. [[#1303](https://github.com/falcosecurity/falco/pull/1303)] - [@leogr](https://github.com/leogr)
|
||||
* new: libyaml is now bundled in the release process. Users can now avoid installing libyaml directly when getting Falco from the official release. [[#1252](https://github.com/falcosecurity/falco/pull/1252)] - [@fntlnz](https://github.com/fntlnz)
|
||||
|
||||
|
||||
### Minor Changes
|
||||
|
||||
* docs(test): step-by-step instructions to run integration tests locally [[#1313](https://github.com/falcosecurity/falco/pull/1313)] - [@leodido](https://github.com/leodido)
|
||||
* update: renameat2 syscall support [[#1355](https://github.com/falcosecurity/falco/pull/1355)] - [@fntlnz](https://github.com/fntlnz)
|
||||
* update: support for 5.8.x kernels [[#1355](https://github.com/falcosecurity/falco/pull/1355)] - [@fntlnz](https://github.com/fntlnz)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix(userspace/falco): correct the fallback mechanism for loading the kernel module [[#1366](https://github.com/falcosecurity/falco/pull/1366)] - [@leogr](https://github.com/leogr)
|
||||
* fix(falco-driver-loader): script crashing when using arguments [[#1330](https://github.com/falcosecurity/falco/pull/1330)] - [@antoinedeschenes](https://github.com/antoinedeschenes)
|
||||
|
||||
|
||||
### Rule Changes
|
||||
|
||||
* rule(macro user_trusted_containers): add `sysdig/node-image-analyzer` and `sysdig/agent-slim` [[#1321](https://github.com/falcosecurity/falco/pull/1321)] - [@Kaizhe](https://github.com/Kaizhe)
|
||||
* rule(macro falco_privileged_images): add `docker.io/falcosecurity/falco` [[#1326](https://github.com/falcosecurity/falco/pull/1326)] - [@nvanheuverzwijn](https://github.com/nvanheuverzwijn)
|
||||
* rule(EphemeralContainers Created): add new rule to detect ephemeral container created [[#1339](https://github.com/falcosecurity/falco/pull/1339)] - [@Kaizhe](https://github.com/Kaizhe)
|
||||
* rule(macro user_read_sensitive_file_containers): replace endswiths with exact image repo name [[#1349](https://github.com/falcosecurity/falco/pull/1349)] - [@Kaizhe](https://github.com/Kaizhe)
|
||||
* rule(macro user_trusted_containers): replace endswiths with exact image repo name [[#1349](https://github.com/falcosecurity/falco/pull/1349)] - [@Kaizhe](https://github.com/Kaizhe)
|
||||
* rule(macro user_privileged_containers): replace endswiths with exact image repo name [[#1349](https://github.com/falcosecurity/falco/pull/1349)] - [@Kaizhe](https://github.com/Kaizhe)
|
||||
* rule(macro trusted_images_query_miner_domain_dns): replace endswiths with exact image repo name [[#1349](https://github.com/falcosecurity/falco/pull/1349)] - [@Kaizhe](https://github.com/Kaizhe)
|
||||
* rule(macro falco_privileged_containers): append "/" to quay.io/sysdig [[#1349](https://github.com/falcosecurity/falco/pull/1349)] - [@Kaizhe](https://github.com/Kaizhe)
|
||||
* rule(list falco_privileged_images): add images docker.io/sysdig/agent-slim and docker.io/sysdig/node-image-analyzer [[#1349](https://github.com/falcosecurity/falco/pull/1349)] - [@Kaizhe](https://github.com/Kaizhe)
|
||||
* rule(list falco_sensitive_mount_images): add image docker.io/sysdig/agent-slim [[#1349](https://github.com/falcosecurity/falco/pull/1349)] - [@Kaizhe](https://github.com/Kaizhe)
|
||||
* rule(list k8s_containers): prepend docker.io to images [[#1349](https://github.com/falcosecurity/falco/pull/1349)] - [@Kaizhe](https://github.com/Kaizhe)
|
||||
* rule(macro exe_running_docker_save): add better support for centos [[#1350](https://github.com/falcosecurity/falco/pull/1350)] - [@admiral0](https://github.com/admiral0)
|
||||
* rule(macro rename): add `renameat2` syscall [[#1359](https://github.com/falcosecurity/falco/pull/1359)] - [@leogr](https://github.com/leogr)
|
||||
* rule(Read sensitive file untrusted): add trusted images into whitelist [[#1327](https://github.com/falcosecurity/falco/pull/1327)] - [@Kaizhe](https://github.com/Kaizhe)
|
||||
* rule(Pod Created in Kube Namespace): add new list k8s_image_list as white list [[#1336](https://github.com/falcosecurity/falco/pull/1336)] - [@Kaizhe](https://github.com/Kaizhe)
|
||||
* rule(list allowed_k8s_users): add "kubernetes-admin" user [[#1323](https://github.com/falcosecurity/falco/pull/1323)] - [@leogr](https://github.com/leogr)
|
||||
This file documents all notable changes to Falco. The release numbering uses [semantic versioning](http://semver.org).
|
||||
|
||||
## v0.24.0
|
||||
|
||||
|
||||
143
CMakeLists.txt
143
CMakeLists.txt
@@ -16,17 +16,6 @@ project(falco)
|
||||
|
||||
option(USE_BUNDLED_DEPS "Bundle hard to find dependencies into the Falco binary" OFF)
|
||||
option(BUILD_WARNINGS_AS_ERRORS "Enable building with -Wextra -Werror flags" OFF)
|
||||
option(MINIMAL_BUILD "Build a minimal version of Falco, containing only the engine and basic input/output (EXPERIMENTAL)" OFF)
|
||||
option(MUSL_OPTIMIZED_BUILD "Enable if you want a musl optimized build" OFF)
|
||||
|
||||
# We shouldn't need to set this, see https://gitlab.kitware.com/cmake/cmake/-/issues/16419
|
||||
option(EP_UPDATE_DISCONNECTED "ExternalProject update disconnected" OFF)
|
||||
if (${EP_UPDATE_DISCONNECTED})
|
||||
set_property(
|
||||
DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
PROPERTY EP_UPDATE_DISCONNECTED TRUE)
|
||||
endif()
|
||||
|
||||
|
||||
# Elapsed time
|
||||
# set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CMAKE_COMMAND} -E time") # TODO(fntlnz, leodido): add a flag to enable this
|
||||
@@ -61,15 +50,7 @@ else()
|
||||
endif()
|
||||
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
||||
|
||||
if(MINIMAL_BUILD)
|
||||
set(MINIMAL_BUILD_FLAGS "-DMINIMAL_BUILD")
|
||||
endif()
|
||||
|
||||
if(MUSL_OPTIMIZED_BUILD)
|
||||
set(MUSL_FLAGS "-static -Os")
|
||||
endif()
|
||||
|
||||
set(CMAKE_COMMON_FLAGS "-Wall -ggdb ${DRAIOS_FEATURE_FLAGS} ${MINIMAL_BUILD_FLAGS} ${MUSL_FLAGS}")
|
||||
set(CMAKE_COMMON_FLAGS "-Wall -ggdb ${DRAIOS_FEATURE_FLAGS}")
|
||||
|
||||
if(BUILD_WARNINGS_AS_ERRORS)
|
||||
set(CMAKE_SUPPRESSED_WARNINGS
|
||||
@@ -92,7 +73,7 @@ include(GetFalcoVersion)
|
||||
set(PACKAGE_NAME "falco")
|
||||
set(PROBE_NAME "falco")
|
||||
set(PROBE_DEVICE_NAME "falco")
|
||||
set(DRIVERS_REPO "https://download.falco.org/driver")
|
||||
set(DRIVERS_REPO "https://dl.bintray.com/falcosecurity/driver")
|
||||
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||
set(CMAKE_INSTALL_PREFIX
|
||||
/usr
|
||||
@@ -124,31 +105,79 @@ set(CURSES_NEED_NCURSES TRUE)
|
||||
find_package(Curses REQUIRED)
|
||||
message(STATUS "Found ncurses: include: ${CURSES_INCLUDE_DIR}, lib: ${CURSES_LIBRARIES}")
|
||||
|
||||
# b64
|
||||
include(b64)
|
||||
# libb64
|
||||
|
||||
set(B64_SRC "${PROJECT_BINARY_DIR}/b64-prefix/src/b64")
|
||||
message(STATUS "Using bundled b64 in '${B64_SRC}'")
|
||||
set(B64_INCLUDE "${B64_SRC}/include")
|
||||
set(B64_LIB "${B64_SRC}/src/libb64.a")
|
||||
ExternalProject_Add(
|
||||
b64
|
||||
URL "https://github.com/libb64/libb64/archive/v1.2.1.zip"
|
||||
URL_HASH "SHA256=665134c2b600098a7ebd3d00b6a866cb34909a6d48e0e37a0eda226a4ad2638a"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND "")
|
||||
|
||||
# yaml-cpp
|
||||
include(yaml-cpp)
|
||||
|
||||
if(NOT MINIMAL_BUILD)
|
||||
# OpenSSL
|
||||
include(OpenSSL)
|
||||
# OpenSSL
|
||||
include(OpenSSL)
|
||||
|
||||
# libcurl
|
||||
include(cURL)
|
||||
endif()
|
||||
# libcurl
|
||||
include(cURL)
|
||||
|
||||
# LuaJIT
|
||||
include(luajit)
|
||||
set(LUAJIT_SRC "${PROJECT_BINARY_DIR}/luajit-prefix/src/luajit/src")
|
||||
message(STATUS "Using bundled LuaJIT in '${LUAJIT_SRC}'")
|
||||
set(LUAJIT_INCLUDE "${LUAJIT_SRC}")
|
||||
set(LUAJIT_LIB "${LUAJIT_SRC}/libluajit.a")
|
||||
ExternalProject_Add(
|
||||
luajit
|
||||
URL "https://github.com/LuaJIT/LuaJIT/archive/v2.0.3.tar.gz"
|
||||
URL_HASH "SHA256=8da3d984495a11ba1bce9a833ba60e18b532ca0641e7d90d97fafe85ff014baa"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND "")
|
||||
|
||||
# Lpeg
|
||||
include(lpeg)
|
||||
set(LPEG_SRC "${PROJECT_BINARY_DIR}/lpeg-prefix/src/lpeg")
|
||||
set(LPEG_LIB "${PROJECT_BINARY_DIR}/lpeg-prefix/src/lpeg/build/lpeg.a")
|
||||
message(STATUS "Using bundled lpeg in '${LPEG_SRC}'")
|
||||
set(LPEG_DEPENDENCIES "")
|
||||
list(APPEND LPEG_DEPENDENCIES "luajit")
|
||||
ExternalProject_Add(
|
||||
lpeg
|
||||
DEPENDS ${LPEG_DEPENDENCIES}
|
||||
URL "http://www.inf.puc-rio.br/~roberto/lpeg/lpeg-1.0.2.tar.gz"
|
||||
URL_HASH "SHA256=48d66576051b6c78388faad09b70493093264588fcd0f258ddaab1cdd4a15ffe"
|
||||
BUILD_COMMAND LUA_INCLUDE=${LUAJIT_INCLUDE} "${PROJECT_SOURCE_DIR}/scripts/build-lpeg.sh" "${LPEG_SRC}/build"
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND ""
|
||||
INSTALL_COMMAND "")
|
||||
|
||||
# libyaml
|
||||
include(libyaml)
|
||||
|
||||
# lyaml
|
||||
include(lyaml)
|
||||
set(LYAML_SRC "${PROJECT_BINARY_DIR}/lyaml-prefix/src/lyaml/ext/yaml")
|
||||
set(LYAML_LIB "${LYAML_SRC}/.libs/yaml.a")
|
||||
message(STATUS "Using bundled lyaml in '${LYAML_SRC}'")
|
||||
set(LYAML_DEPENDENCIES "")
|
||||
list(APPEND LYAML_DEPENDENCIES "luajit")
|
||||
ExternalProject_Add(
|
||||
lyaml
|
||||
DEPENDS ${LYAML_DEPENDENCIES}
|
||||
URL "https://github.com/gvvaughan/lyaml/archive/release-v6.0.tar.gz"
|
||||
URL_HASH "SHA256=9d7cf74d776999ff6f758c569d5202ff5da1f303c6f4229d3b41f71cd3a3e7a7"
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND ./configure --enable-static LIBS=-lyaml LUA_INCLUDE=-I${LUAJIT_INCLUDE} LUA=${LUAJIT_SRC}/luajit
|
||||
INSTALL_COMMAND sh -c
|
||||
"cp -R ${PROJECT_BINARY_DIR}/lyaml-prefix/src/lyaml/lib/* ${PROJECT_SOURCE_DIR}/userspace/engine/lua")
|
||||
|
||||
# One TBB
|
||||
set(TBB_SRC "${PROJECT_BINARY_DIR}/tbb-prefix/src/tbb")
|
||||
@@ -167,31 +196,26 @@ ExternalProject_Add(
|
||||
BUILD_BYPRODUCTS ${TBB_LIB}
|
||||
INSTALL_COMMAND "")
|
||||
|
||||
if(NOT MINIMAL_BUILD)
|
||||
# civetweb
|
||||
set(CIVETWEB_SRC "${PROJECT_BINARY_DIR}/civetweb-prefix/src/civetweb/")
|
||||
set(CIVETWEB_LIB "${CIVETWEB_SRC}/install/lib/libcivetweb.a")
|
||||
set(CIVETWEB_INCLUDE_DIR "${CIVETWEB_SRC}/install/include")
|
||||
message(STATUS "Using bundled civetweb in '${CIVETWEB_SRC}'")
|
||||
ExternalProject_Add(
|
||||
civetweb
|
||||
URL "https://github.com/civetweb/civetweb/archive/v1.11.tar.gz"
|
||||
URL_HASH "SHA256=de7d5e7a2d9551d325898c71e41d437d5f7b51e754b242af897f7be96e713a42"
|
||||
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E make_directory ${CIVETWEB_SRC}/install/lib
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${CIVETWEB_SRC}/install/include
|
||||
BUILD_IN_SOURCE 1
|
||||
BUILD_COMMAND ${CMD_MAKE} COPT="-DNO_FILES" WITH_CPP=1
|
||||
BUILD_BYPRODUCTS ${CIVETWEB_LIB}
|
||||
INSTALL_COMMAND ${CMD_MAKE} COPT="-DNO_FILES" install-lib install-headers PREFIX=${CIVETWEB_SRC}/install "WITH_CPP=1")
|
||||
endif()
|
||||
# civetweb
|
||||
set(CIVETWEB_SRC "${PROJECT_BINARY_DIR}/civetweb-prefix/src/civetweb/")
|
||||
set(CIVETWEB_LIB "${CIVETWEB_SRC}/install/lib/libcivetweb.a")
|
||||
set(CIVETWEB_INCLUDE_DIR "${CIVETWEB_SRC}/install/include")
|
||||
message(STATUS "Using bundled civetweb in '${CIVETWEB_SRC}'")
|
||||
ExternalProject_Add(
|
||||
civetweb
|
||||
URL "https://github.com/civetweb/civetweb/archive/v1.11.tar.gz"
|
||||
URL_HASH "SHA256=de7d5e7a2d9551d325898c71e41d437d5f7b51e754b242af897f7be96e713a42"
|
||||
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E make_directory ${CIVETWEB_SRC}/install/lib
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${CIVETWEB_SRC}/install/include
|
||||
BUILD_IN_SOURCE 1
|
||||
BUILD_COMMAND ${CMD_MAKE} COPT="-DNO_FILES" WITH_CPP=1
|
||||
INSTALL_COMMAND ${CMD_MAKE} COPT="-DNO_FILES" install-lib install-headers PREFIX=${CIVETWEB_SRC}/install "WITH_CPP=1")
|
||||
|
||||
#string-view-lite
|
||||
include(DownloadStringViewLite)
|
||||
|
||||
if(NOT MINIMAL_BUILD)
|
||||
# gRPC
|
||||
include(gRPC)
|
||||
endif()
|
||||
# gRPC
|
||||
include(gRPC)
|
||||
|
||||
# sysdig
|
||||
include(sysdig)
|
||||
@@ -199,13 +223,11 @@ include(sysdig)
|
||||
# Installation
|
||||
install(FILES falco.yaml DESTINATION "${FALCO_ETC_DIR}")
|
||||
|
||||
if(NOT MINIMAL_BUILD)
|
||||
# Coverage
|
||||
include(Coverage)
|
||||
# Coverage
|
||||
include(Coverage)
|
||||
|
||||
# Tests
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
# Tests
|
||||
add_subdirectory(test)
|
||||
|
||||
# Rules
|
||||
add_subdirectory(rules)
|
||||
@@ -216,9 +238,6 @@ add_subdirectory(docker)
|
||||
# Clang format
|
||||
# add_custom_target(format COMMAND clang-format --style=file -i $<TARGET_PROPERTY:falco,SOURCES> COMMENT "Formatting ..." VERBATIM)
|
||||
|
||||
# Static analysis
|
||||
include(static-analysis)
|
||||
|
||||
# Shared build variables
|
||||
set(FALCO_SINSP_LIBRARY sinsp)
|
||||
set(FALCO_SHARE_DIR share/falco)
|
||||
|
||||
38
CODE_OF_CONDUCT.md
Normal file
38
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# CNCF Community Code of Conduct v1.0
|
||||
|
||||
## Contributor Code of Conduct
|
||||
|
||||
As contributors and maintainers of this project, and in the interest of fostering
|
||||
an open and welcoming community, we pledge to respect all people who contribute
|
||||
through reporting issues, posting feature requests, updating documentation,
|
||||
submitting pull requests or patches, and other activities.
|
||||
|
||||
We are committed to making participation in this project a harassment-free experience for
|
||||
everyone, regardless of level of experience, gender, gender identity and expression,
|
||||
sexual orientation, disability, personal appearance, body size, race, ethnicity, age,
|
||||
religion, or nationality.
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery
|
||||
* Personal attacks
|
||||
* Trolling or insulting/derogatory comments
|
||||
* Public or private harassment
|
||||
* Publishing other's private information, such as physical or electronic addresses,
|
||||
without explicit permission
|
||||
* Other unethical or unprofessional conduct.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are not
|
||||
aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers
|
||||
commit themselves to fairly and consistently applying these principles to every aspect
|
||||
of managing this project. Project maintainers who do not follow or enforce the Code of
|
||||
Conduct may be permanently removed from the project team.
|
||||
|
||||
This code of conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community.
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting a CNCF project maintainer, [Sarah Novotny](mailto:sarahnovotny@google.com), and/or [Dan Kohn](mailto:dan@linuxfoundation.org).
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at
|
||||
http://contributor-covenant.org/version/1/2/0/
|
||||
150
CONTRIBUTING.md
Normal file
150
CONTRIBUTING.md
Normal file
@@ -0,0 +1,150 @@
|
||||
# Contributing to Falco
|
||||
|
||||
- [Contributing to Falco](#contributing-to-falco)
|
||||
- [Code of Conduct](#code-of-conduct)
|
||||
- [Issues](#issues)
|
||||
- [Triage issues](#triage-issues)
|
||||
- [More about labels](#more-about-labels)
|
||||
- [Slack](#slack)
|
||||
- [Pull Requests](#pull-requests)
|
||||
- [Commit convention](#commit-convention)
|
||||
- [Rule type](#rule-type)
|
||||
- [Coding Guidelines](#coding-guidelines)
|
||||
- [C++](#c)
|
||||
- [Unit testing](/tests/README.md)
|
||||
- [Developer Certificate Of Origin](#developer-certificate-of-origin)
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
Falco has a
|
||||
[Code of Conduct](CODE_OF_CONDUCT.md)
|
||||
to which all contributors must adhere, please read it before interacting with the repository or the community in any way.
|
||||
|
||||
## Issues
|
||||
|
||||
Issues are the heartbeat ❤️ of the Falco project, there are mainly three kinds of issues you can open:
|
||||
|
||||
- Bug report: you believe you found a problem in Falco and you want to discuss and get it fixed,
|
||||
creating an issue with the **bug report template** is the best way to do so.
|
||||
- Enhancement: any kind of new feature need to be discussed in this kind of issue, do you want a new rule or a new feature? This is the kind of issue you want to open. Be very good at explaining your intent, it's always important that others can understand what you mean in order to discuss, be open and collaborative in letting others help you getting this done!
|
||||
- Failing tests: you noticed a flaky test or a problem with a build? This is the kind of issue to triage that!
|
||||
|
||||
The best way to get **involved** in the project is through issues, you can help in many ways:
|
||||
|
||||
- Issues triaging: participating in the discussion and adding details to open issues is always a good thing,
|
||||
sometimes issues need to be verified, you could be the one writing a test case to fix a bug!
|
||||
- Helping to resolve the issue: you can help in getting it fixed in many ways, more often by opening a pull request.
|
||||
|
||||
### Triage issues
|
||||
|
||||
We need help in categorizing issues. Thus any help is welcome!
|
||||
|
||||
When you triage an issue, you:
|
||||
|
||||
* assess whether it has merit or not
|
||||
|
||||
* quickly close it by correctly answering a question
|
||||
|
||||
* point the reporter to a resource or documentation answering the issue
|
||||
|
||||
* tag it via labels, projects, or milestones
|
||||
|
||||
* take ownership submitting a PR for it, in case you want 😇
|
||||
|
||||
#### More about labels
|
||||
|
||||
These guidelines are not set in stone and are subject to change.
|
||||
|
||||
Anyway a `kind/*` label for any issue is mandatory.
|
||||
|
||||
This is the current [label set](https://github.com/falcosecurity/falco/labels) we have.
|
||||
|
||||
You can use commands - eg., `/label <some-label>` to add (or remove) labels or manually do it.
|
||||
|
||||
The commands available are the following ones:
|
||||
|
||||
```
|
||||
/[remove-](area|kind|priority|triage|label)
|
||||
```
|
||||
|
||||
Some examples:
|
||||
|
||||
* `/area rules`
|
||||
* `/remove-area rules`
|
||||
* `/kind kernel-module`
|
||||
* `/label good-first-issue`
|
||||
* `/triage duplicate`
|
||||
* `/triage unresolved`
|
||||
* `/triage not-reproducible`
|
||||
* `/triage support`
|
||||
* ...
|
||||
|
||||
### Slack
|
||||
|
||||
Other discussion, and **support requests** should go through the `#falco` channel in the Kubernetes slack, please join [here](https://slack.k8s.io/).
|
||||
|
||||
## Pull Requests
|
||||
|
||||
Thanks for taking time to make a [pull request](https://help.github.com/articles/about-pull-requests) (hereafter PR).
|
||||
|
||||
In the PR body, feel free to add an area label if appropriate by typing `/area <AREA>`, PRs will also
|
||||
need a kind, make sure to specify the appropriate one by typing `/kind <KIND>`.
|
||||
|
||||
The list of labels is [here](https://github.com/falcosecurity/falco/labels).
|
||||
|
||||
Also feel free to suggest a reviewer with `/cc @theirname`, or to assign an assignee using `/assign @nickname`.
|
||||
|
||||
Once your reviewer is happy, they will say `/lgtm` which will apply the
|
||||
`lgtm` label, and will apply the `approved` label if they are an
|
||||
[owner](/OWNERS).
|
||||
|
||||
Your PR will be automatically merged once it has the `lgtm` and `approved`
|
||||
labels, does not have any `do-not-merge/*` labels, and all status checks (eg., rebase, tests, DCO) are positive.
|
||||
|
||||
### Commit convention
|
||||
|
||||
As commit convention, we adopt [Conventional Commits v1.0.0](https://www.conventionalcommits.org/en/v1.0.0/), we have an history
|
||||
of commits that do not adopt the convention but any new commit must follow it to be eligible for merge.
|
||||
|
||||
#### Rule type
|
||||
|
||||
Besides the classic types, we adopt a type for rules, `rule(<scope>):`.
|
||||
Example:
|
||||
|
||||
```
|
||||
rule(Write below monitored dir): make sure monitored dirs are monitored.
|
||||
```
|
||||
|
||||
Each rule change must be on its own commit, if a change to a macro is done while changing a rule they can go together but only one rule per commit must happen.
|
||||
|
||||
If you are changing only a macro, the commit will look like this:
|
||||
|
||||
```
|
||||
rule(macro user_known_write_monitored_dir_conditions): make sure conditions are great
|
||||
```
|
||||
|
||||
## Coding Guidelines
|
||||
|
||||
### C++
|
||||
|
||||
* File `userspace/engine/banned.h` defines some functions as invalid tokens. These functions are not allowed to be used in the codebase. Whenever creating a new cpp file, include the `"banned.h"` headers. This ensures that the banned functions are not compiled.
|
||||
|
||||
A complete list of banned functions can be found [here](./userspace/engine/banned.h).
|
||||
|
||||
## Developer Certificate Of Origin
|
||||
|
||||
The [Developer Certificate of Origin (DCO)](https://developercertificate.org/) is a lightweight way for contributors to certify that they wrote or otherwise have the right to submit the code they are contributing to the project.
|
||||
|
||||
Contributors to the Falco project sign-off that they adhere to these requirements by adding a `Signed-off-by` line to commit messages.
|
||||
|
||||
```
|
||||
This is my commit message
|
||||
|
||||
Signed-off-by: John Poiana <jpoiana@falco.org>
|
||||
```
|
||||
|
||||
Git even has a `-s` command line option to append this automatically to your commit message:
|
||||
|
||||
```
|
||||
$ git commit -s -m 'This is my commit message'
|
||||
```
|
||||
91
README.md
91
README.md
@@ -3,11 +3,11 @@
|
||||
|
||||
<hr>
|
||||
|
||||
[](https://circleci.com/gh/falcosecurity/falco) [](https://bestpractices.coreinfrastructure.org/projects/2317) [](./COPYING)
|
||||
# The Falco Project
|
||||
|
||||
Want to talk? Join us on the [#falco](https://kubernetes.slack.com/archives/CMWH3EH32) channel in the [Kubernetes Slack](https://slack.k8s.io).
|
||||
[](https://circleci.com/gh/falcosecurity/falco) [](https://bestpractices.coreinfrastructure.org/projects/2317) [](COPYING)
|
||||
|
||||
### Latest releases
|
||||
#### Latest releases
|
||||
|
||||
Read the [change log](CHANGELOG.md).
|
||||
|
||||
@@ -19,89 +19,66 @@ Read the [change log](CHANGELOG.md).
|
||||
|
||||
---
|
||||
|
||||
The Falco Project, originally created by [Sysdig](https://sysdig.com), is an incubating [CNCF](https://cncf.io) open source cloud native runtime security tool.
|
||||
Falco makes it easy to consume kernel events, and enrich those events with information from Kubernetes and the rest of the cloud native stack.
|
||||
Falco has a rich rule set of security rules specifically built for Kubernetes, Linux, and cloud-native.
|
||||
If a rule is violated in a system, Falco will send an alert notifying the user of the violation and its severity.
|
||||
Falco is a behavioral activity monitor designed to detect anomalous activity in your applications. Falco audits a system at the most fundamental level, the kernel. Falco then enriches this data with other input streams such as container runtime metrics, and Kubernetes metrics. Falco lets you continuously monitor and detect container, application, host, and network activity—all in one place—from one source of data, with one set of rules.
|
||||
|
||||
### Installing Falco
|
||||
Falco is hosted by the Cloud Native Computing Foundation (CNCF) as a sandbox level project. If you are an organization that wants to help shape the evolution of technologies that are container-packaged, dynamically-scheduled and microservices-oriented, consider joining the CNCF. For details read the [Falco CNCF project proposal](https://github.com/cncf/toc/tree/master/proposals/falco.adoc).
|
||||
|
||||
If you would like to run Falco in **production** please adhere to the [official installation guide](https://falco.org/docs/installation/).
|
||||
#### What kind of behaviors can Falco detect?
|
||||
|
||||
##### Kubernetes
|
||||
Falco can detect and alert on any behavior that involves making Linux system calls. Falco alerts can be triggered by the use of specific system calls, their arguments, and by properties of the calling process. For example, Falco can easily detect incidents including but not limited to:
|
||||
|
||||
| Tool | Link | Note |
|
||||
|----------|--------------------------------------------------------------------------------------------|--------------------------------------------------------------------|
|
||||
| Helm | [Chart Repository](https://github.com/falcosecurity/charts/tree/master/falco#introduction) | The Falco community offers regular helm chart releases. |
|
||||
| Minikube | [Tutorial](https://falco.org/docs/getting-started/third-party/#minikube) | The Falco driver has been baked into minikube for easy deployment. |
|
||||
| Kind | [Tutorial](https://falco.org/docs/getting-started/third-party/#kind) | Running Falco with kind requires a driver on the host system. |
|
||||
| GKE | [Tutorial](https://falco.org/docs/getting-started/third-party/#gke) | We suggest using the eBPF driver for running Falco on GKE. |
|
||||
|
||||
### Developing
|
||||
|
||||
Falco is designed to be extensible such that it can be built into cloud-native applications and infrastructure.
|
||||
|
||||
Falco has a [gRPC](https://falco.org/docs/grpc/) endpoint and an API defined in [protobuf](https://github.com/falcosecurity/falco/blob/master/userspace/falco/outputs.proto).
|
||||
The Falco Project supports various SDKs for this endpoint.
|
||||
|
||||
##### SDKs
|
||||
|
||||
| Language | Repository |
|
||||
|----------|---------------------------------------------------------|
|
||||
| Go | [client-go](https://github.com/falcosecurity/client-go) |
|
||||
| Rust | [client-rs](https://github.com/falcosecurity/client-rs) |
|
||||
| Python | [client-py](https://github.com/falcosecurity/client-py) |
|
||||
|
||||
|
||||
### What can Falco detect?
|
||||
|
||||
Falco can detect and alert on any behavior that involves making Linux system calls.
|
||||
Falco alerts can be triggered by the use of specific system calls, their arguments, and by properties of the calling process.
|
||||
For example, Falco can easily detect incidents including but not limited to:
|
||||
|
||||
- A shell is running inside a container or pod in Kubernetes.
|
||||
- A shell is running inside a container.
|
||||
- A container is running in privileged mode, or is mounting a sensitive path, such as `/proc`, from the host.
|
||||
- A server process is spawning a child process of an unexpected type.
|
||||
- Unexpected read of a sensitive file, such as `/etc/shadow`.
|
||||
- A non-device file is written to `/dev`.
|
||||
- A standard system binary, such as `ls`, is making an outbound network connection.
|
||||
- A privileged pod is started in a Kubernetes cluster.
|
||||
|
||||
### Documentation
|
||||
|
||||
The [Official Documentation](https://falco.org/docs/) is the best resource to learn about Falco.
|
||||
### Installing Falco
|
||||
|
||||
### Join the Community
|
||||
You can find the latest release downloads on the official [release archive](https://bintray.com/falcosecurity)
|
||||
|
||||
Furthermore the comprehensive [installation guide](https://falco.org/docs/installation/) for Falco is available in the documentation website.
|
||||
|
||||
#### How do you compare Falco with other security tools?
|
||||
|
||||
One of the questions we often get when we talk about Falco is “How does Falco differ from other Linux security tools such as SELinux, AppArmor, Auditd, etc.?”. We wrote a [blog post](https://sysdig.com/blog/selinux-seccomp-falco-technical-discussion/) comparing Falco with other tools.
|
||||
|
||||
|
||||
Documentation
|
||||
---
|
||||
|
||||
See [Falco Documentation](https://falco.org/docs/) to quickly get started using Falco.
|
||||
|
||||
Join the Community
|
||||
---
|
||||
|
||||
To get involved with The Falco Project please visit [the community repository](https://github.com/falcosecurity/community) to find more.
|
||||
|
||||
How to reach out?
|
||||
License Terms
|
||||
---
|
||||
|
||||
- Join the #falco channel on the [Kubernetes Slack](https://slack.k8s.io)
|
||||
- [Join the Falco mailing list](https://lists.cncf.io/g/cncf-falco-dev)
|
||||
- [Read the Falco documentation](https://falco.org/docs/)
|
||||
Falco is licensed to you under the [Apache 2.0](./COPYING) open source license.
|
||||
|
||||
Contributing
|
||||
---
|
||||
|
||||
### Contributing
|
||||
See the [CONTRIBUTING.md](./CONTRIBUTING.md).
|
||||
|
||||
See the [CONTRIBUTING.md](https://github.com/falcosecurity/.github/blob/master/CONTRIBUTING.md).
|
||||
Security
|
||||
---
|
||||
|
||||
### Security Audit
|
||||
|
||||
A third party security audit was performed by Cure53, you can see the full report [here](./audits/SECURITY_AUDIT_2019_07.pdf).
|
||||
|
||||
### Reporting security vulnerabilities
|
||||
|
||||
Please report security vulnerabilities following the community process documented [here](https://github.com/falcosecurity/.github/blob/master/SECURITY.md).
|
||||
|
||||
### License Terms
|
||||
|
||||
Falco is licensed to you under the [Apache 2.0](./COPYING) open source license.
|
||||
|
||||
|
||||
[1]: https://dl.bintray.com/falcosecurity/rpm-dev
|
||||
[2]: https://dl.bintray.com/falcosecurity/rpm
|
||||
[3]: https://dl.bintray.com/falcosecurity/deb-dev/stable
|
||||
[4]: https://dl.bintray.com/falcosecurity/deb/stable
|
||||
[5]: https://dl.bintray.com/falcosecurity/bin-dev/x86_64
|
||||
[6]: https://dl.bintray.com/falcosecurity/bin/x86_64
|
||||
[6]: https://dl.bintray.com/falcosecurity/bin/x86_64
|
||||
51
RELEASE.md
51
RELEASE.md
@@ -4,21 +4,19 @@ Our release process is mostly automated, but we still need some manual steps to
|
||||
|
||||
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.
|
||||
|
||||
A release happens every two months ([as per community discussion](https://github.com/falcosecurity/community/blob/master/meeting-notes/2020-09-30.md#agenda)), and we need to assign owners for each (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). Note that hotfix releases can happen as soon as it is needed.
|
||||
Releases happen on a monthly cadence, towards the 16th of the on-going month, and we need to assign owners for each (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). Note that hotfix releases can happen as soon as it is needed.
|
||||
|
||||
Finally, on the proposed due date the assignees for the upcoming release proceed with the processes described below.
|
||||
|
||||
## Pre-Release Checklist
|
||||
|
||||
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
|
||||
- Find the LAST release (-1) and use `YYYY-MM-DD` as the day before of the [latest release](https://github.com/falcosecurity/falco/releases)
|
||||
- Let `YYYY-MM-DD` the day before of the [latest release](https://github.com/falcosecurity/falco/releases)
|
||||
- Check the release note block of every PR matching the `is:pr is:merged closed:>YYYY-MM-DD` [filter](https://github.com/falcosecurity/falco/pulls?q=is%3Apr+is%3Amerged+closed%3A%3EYYYY-MM-DD)
|
||||
- Ensure the release note block follows the [commit convention](https://github.com/falcosecurity/falco/blob/master/CONTRIBUTING.md#commit-convention), otherwise fix its content
|
||||
- If the PR has no milestone, assign it to the milestone currently undergoing release
|
||||
- Check issues without a milestone (using [is:pr is:merged no:milestone closed:>YYYY-MM-DD](https://github.com/falcosecurity/falco/pulls?q=is%3Apr+is%3Amerged+no%3Amilestone+closed%3A%3EYYYY-MM-DD) filter) and add them to the milestone currently undergoing release
|
||||
- Double-check that there are no more merged PRs without the target milestone assigned with the `is:pr is:merged no:milestone closed:>YYYY-MM-DD` [filters](https://github.com/falcosecurity/falco/pulls?q=is%3Apr+is%3Amerged+no%3Amilestone+closed%3A%3EYYYY-MM-DD), if any, fix them
|
||||
- Check issues without a milestone (using [is:pr is:merged no:milestone closed:>YYYT-MM-DD](https://github.com/falcosecurity/falco/pulls?q=is%3Apr+is%3Amerged+no%3Amilestone+closed%3A%3EYYYT-MM-DD) filter) and add them to the milestone currently undergoing release
|
||||
- Double-check that there are no more merged PRs without the target milestone assigned with the `is:pr is:merged no:milestone closed:>YYYT-MM-DD` [filters](https://github.com/falcosecurity/falco/pulls?q=is%3Apr+is%3Amerged+no%3Amilestone+closed%3A%3EYYYT-MM-DD), if any, fix them
|
||||
|
||||
### 2. Milestones
|
||||
|
||||
@@ -30,15 +28,14 @@ Before cutting a release we need to do some homework in the Falco repository. Th
|
||||
- If any, manually correct it then open an issue to automate version number bumping later
|
||||
- Versions table in the `README.md` update itself automatically
|
||||
- Generate the change log https://github.com/leodido/rn2md, or https://fs.fntlnz.wtf/falco/milestones-changelog.txt for the lazy people (it updates every 5 minutes)
|
||||
- If you review timeout errors with `rn2md` try to generate an GitHub Oauth access token and use `-t`
|
||||
- Add the latest changes on top the previous `CHANGELOG.md`
|
||||
- Add the lastest changes on top the previous `CHANGELOG.md`
|
||||
- Submit a PR with the above modifications
|
||||
- Await PR approval
|
||||
- Close the completed milestone as soon as the PR is merged
|
||||
- Close the completed milestone as soon PR is merged
|
||||
|
||||
## Release
|
||||
|
||||
Now assume `x.y.z` is the new version.
|
||||
Let `x.y.z` the new version.
|
||||
|
||||
### 1. Create a tag
|
||||
|
||||
@@ -61,45 +58,21 @@ Now assume `x.y.z` is the new version.
|
||||
- Use `x.y.z` both as tag version and release title
|
||||
- Use the following template to fill the release description:
|
||||
```
|
||||
<!-- Substitute x.y.z with the current release version -->
|
||||
|
||||
| Packages | Download |
|
||||
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| rpm | [](https://dl.bintray.com/falcosecurity/rpm/falco-x.y.z-x86_64.rpm) |
|
||||
| deb | [](https://dl.bintray.com/falcosecurity/deb/stable/falco-x.y.z-x86_64.deb) |
|
||||
| tgz | [](https://dl.bintray.com/falcosecurity/bin/x86_64/falco-x.y.z-x86_64.deb) |
|
||||
|
||||
| Images |
|
||||
| --------------------------------------------------------------- |
|
||||
| `docker pull docker.io/falcosecurity/falco:_tag_` |
|
||||
| `docker pull docker.io/falcosecurity/falco-driver-loader:_tag_` |
|
||||
| `docker pull docker.io/falcosecurity/falco-no-driver:_tag_` |
|
||||
|
||||
<!-- Copy the relevant part of the changelog here -->
|
||||
|
||||
### Statistics
|
||||
|
||||
| Merged PRs | Number |
|
||||
| --------------- | ------ |
|
||||
| Not user-facing | x |
|
||||
| Release note | x |
|
||||
| Total | x |
|
||||
| Merged PRs | Number |
|
||||
|-------------------|---------|
|
||||
| Not user-facing | x |
|
||||
| Release note | x |
|
||||
| Total | x |
|
||||
|
||||
<!-- Calculate stats and fill the above table -->
|
||||
```
|
||||
|
||||
- Finally, publish the release!
|
||||
|
||||
### 3. Update the meeting notes
|
||||
|
||||
For each release we archive the meeting notes in git for historical purposes.
|
||||
|
||||
- The notes from the Falco meetings can be [found here](https://hackmd.io/6sEAlInlSaGnLz2FnFz21A).
|
||||
- Note: There may be other notes from working groups that can optionally be added as well as needed.
|
||||
- Add the entire content of the document to a new file in [github.com/falcosecurity/community/tree/master/meeting-notes](https://github.com/falcosecurity/community/tree/master/meeting-notes) as a new file labeled `release-x.y.z.md`
|
||||
- Open up a pull request with the new change.
|
||||
|
||||
|
||||
## Post-Release tasks
|
||||
|
||||
Announce the new release to the world!
|
||||
|
||||
@@ -15,21 +15,6 @@ There are 3 logos available for use in this directory. Use the primary logo unle
|
||||
|
||||
The Falco logo is Apache 2 licensed and free to use in media and publication for the CNCF Falco project.
|
||||
|
||||
### Colors
|
||||
|
||||
| Name | PMS | RGB |
|
||||
|-----------|------|-------------|
|
||||
| Teal | 3125 | 0 174 199 |
|
||||
| Cool Gray | 11 | 83 86 90 |
|
||||
| Black | | 0 0 0 |
|
||||
| Blue-Gray | 7700 | 22 92 125 |
|
||||
| Gold | 1375 | 255 158 27 |
|
||||
| Orange | 171 | 255 92 57 |
|
||||
| Emerald | 3278 | 0 155 119 |
|
||||
| Green | 360 | 108 194 74 |
|
||||
|
||||
The primary colors are those in the first two rows.
|
||||
|
||||
### Slogan
|
||||
|
||||
> Cloud Native Runtime Security
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
set(CPM_DOWNLOAD_VERSION 0.27.2)
|
||||
|
||||
if(CPM_SOURCE_CACHE)
|
||||
set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
|
||||
elseif(DEFINED ENV{CPM_SOURCE_CACHE})
|
||||
set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
|
||||
else()
|
||||
set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
|
||||
endif()
|
||||
|
||||
if(NOT (EXISTS ${CPM_DOWNLOAD_LOCATION}))
|
||||
message(STATUS "Downloading CPM.cmake to ${CPM_DOWNLOAD_LOCATION}")
|
||||
file(DOWNLOAD
|
||||
https://github.com/TheLartians/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
|
||||
${CPM_DOWNLOAD_LOCATION}
|
||||
)
|
||||
endif()
|
||||
|
||||
include(${CPM_DOWNLOAD_LOCATION})
|
||||
@@ -25,20 +25,10 @@ set(CPACK_PROJECT_CONFIG_FILE "${PROJECT_SOURCE_DIR}/cmake/cpack/CMakeCPackOptio
|
||||
set(CPACK_STRIP_FILES "ON")
|
||||
set(CPACK_PACKAGE_RELOCATABLE "OFF")
|
||||
|
||||
if(NOT CPACK_GENERATOR)
|
||||
set(CPACK_GENERATOR DEB RPM TGZ)
|
||||
endif()
|
||||
set(CPACK_GENERATOR DEB RPM TGZ)
|
||||
|
||||
message(STATUS "Using package generators: ${CPACK_GENERATOR}")
|
||||
message(STATUS "Package architecture: ${CMAKE_SYSTEM_PROCESSOR}")
|
||||
set(CPACK_DEBIAN_PACKAGE_SECTION "utils")
|
||||
|
||||
if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64")
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64")
|
||||
endif()
|
||||
if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "arm64")
|
||||
endif()
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64")
|
||||
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://www.falco.org")
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "dkms (>= 2.1.0.0)")
|
||||
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA
|
||||
|
||||
@@ -15,7 +15,7 @@ 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}")
|
||||
message(STATUS "Found string-view-lite: include: ${STRING_VIEW_LITE_INCLUDE}")
|
||||
|
||||
ExternalProject_Add(
|
||||
string-view-lite
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
# "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.
|
||||
#
|
||||
mark_as_advanced(OPENSSL_BINARY)
|
||||
if(NOT USE_BUNDLED_DEPS)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
message(STATUS "Found openssl: include: ${OPENSSL_INCLUDE_DIR}, lib: ${OPENSSL_LIBRARIES}")
|
||||
@@ -21,8 +20,6 @@ if(NOT USE_BUNDLED_DEPS)
|
||||
message(STATUS "Found openssl: binary: ${OPENSSL_BINARY}")
|
||||
endif()
|
||||
else()
|
||||
mark_as_advanced(OPENSSL_BUNDLE_DIR OPENSSL_INSTALL_DIR OPENSSL_INCLUDE_DIR
|
||||
OPENSSL_LIBRARY_SSL OPENSSL_LIBRARY_CRYPTO)
|
||||
set(OPENSSL_BUNDLE_DIR "${PROJECT_BINARY_DIR}/openssl-prefix/src/openssl")
|
||||
set(OPENSSL_INSTALL_DIR "${OPENSSL_BUNDLE_DIR}/target")
|
||||
set(OPENSSL_INCLUDE_DIR "${PROJECT_BINARY_DIR}/openssl-prefix/src/openssl/include")
|
||||
@@ -38,7 +35,7 @@ else()
|
||||
URL "https://github.com/openssl/openssl/archive/OpenSSL_1_0_2n.tar.gz"
|
||||
URL_HASH "SHA256=4f4bc907caff1fee6ff8593729e5729891adcee412049153a3bb4db7625e8364"
|
||||
# END CHANGE for CVE-2017-3735, CVE-2017-3731, CVE-2017-3737, CVE-2017-3738, CVE-2017-3736
|
||||
CONFIGURE_COMMAND ./config no-shared --prefix=${OPENSSL_INSTALL_DIR}
|
||||
CONFIGURE_COMMAND ./config shared --prefix=${OPENSSL_INSTALL_DIR}
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND ${CMD_MAKE} install)
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
set(B64_SRC "${PROJECT_BINARY_DIR}/b64-prefix/src/b64")
|
||||
message(STATUS "Using bundled b64 in '${B64_SRC}'")
|
||||
set(B64_INCLUDE "${B64_SRC}/include")
|
||||
set(B64_LIB "${B64_SRC}/src/libb64.a")
|
||||
externalproject_add(
|
||||
b64
|
||||
URL "https://github.com/libb64/libb64/archive/ce864b17ea0e24a91e77c7dd3eb2d1ac4175b3f0.tar.gz"
|
||||
URL_HASH "SHA256=d07173e66f435e5c77dbf81bd9313f8d0e4a3b4edd4105a62f4f8132ba932811"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
BUILD_BYPRODUCTS ${B64_LIB}
|
||||
INSTALL_COMMAND ""
|
||||
)
|
||||
@@ -19,9 +19,13 @@ else()
|
||||
set(CURL_INCLUDE_DIR "${CURL_BUNDLE_DIR}/include/")
|
||||
set(CURL_LIBRARIES "${CURL_BUNDLE_DIR}/lib/.libs/libcurl.a")
|
||||
|
||||
set(CURL_SSL_OPTION "--with-ssl=${OPENSSL_INSTALL_DIR}")
|
||||
message(STATUS "Using bundled curl in '${CURL_BUNDLE_DIR}'")
|
||||
message(STATUS "Using SSL for curl in '${CURL_SSL_OPTION}'")
|
||||
if(NOT USE_BUNDLED_OPENSSL)
|
||||
set(CURL_SSL_OPTION "--with-ssl")
|
||||
else()
|
||||
set(CURL_SSL_OPTION "--with-ssl=${OPENSSL_INSTALL_DIR}")
|
||||
message(STATUS "Using bundled curl in '${CURL_BUNDLE_DIR}'")
|
||||
message(STATUS "Using SSL for curl in '${CURL_SSL_OPTION}'")
|
||||
endif()
|
||||
|
||||
externalproject_add(
|
||||
curl
|
||||
|
||||
@@ -22,7 +22,6 @@ if(NOT USE_BUNDLED_DEPS)
|
||||
endif()
|
||||
|
||||
# c-ares
|
||||
mark_as_advanced(CARES_INCLUDE CARES_LIB)
|
||||
find_path(CARES_INCLUDE NAMES ares.h)
|
||||
find_library(CARES_LIB NAMES libcares.so)
|
||||
if(CARES_INCLUDE AND CARES_LIB)
|
||||
@@ -32,7 +31,6 @@ if(NOT USE_BUNDLED_DEPS)
|
||||
endif()
|
||||
|
||||
# protobuf
|
||||
mark_as_advanced(PROTOC PROTOBUF_INCLUDE PROTOBUF_LIB)
|
||||
find_program(PROTOC NAMES protoc)
|
||||
find_path(PROTOBUF_INCLUDE NAMES google/protobuf/message.h)
|
||||
find_library(PROTOBUF_LIB NAMES libprotobuf.so)
|
||||
@@ -45,7 +43,6 @@ if(NOT USE_BUNDLED_DEPS)
|
||||
endif()
|
||||
|
||||
# gpr
|
||||
mark_as_advanced(GPR_LIB)
|
||||
find_library(GPR_LIB NAMES gpr)
|
||||
|
||||
if(GPR_LIB)
|
||||
@@ -55,16 +52,12 @@ if(NOT USE_BUNDLED_DEPS)
|
||||
endif()
|
||||
|
||||
# gRPC todo(fntlnz, leodido): check that gRPC version is greater or equal than 1.8.0
|
||||
mark_as_advanced(GRPC_INCLUDE GRPC_SRC
|
||||
GRPC_LIB GRPC_LIBS_ABSOLUTE GRPCPP_LIB GRPC_CPP_PLUGIN)
|
||||
find_path(GRPCXX_INCLUDE NAMES grpc++/grpc++.h)
|
||||
if(GRPCXX_INCLUDE)
|
||||
set(GRPC_INCLUDE ${GRPCXX_INCLUDE})
|
||||
unset(GRPCXX_INCLUDE CACHE)
|
||||
else()
|
||||
find_path(GRPCPP_INCLUDE NAMES grpcpp/grpcpp.h)
|
||||
set(GRPC_INCLUDE ${GRPCPP_INCLUDE})
|
||||
unset(GRPCPP_INCLUDE CACHE)
|
||||
add_definitions(-DGRPC_INCLUDE_IS_GRPCPP=1)
|
||||
endif()
|
||||
find_library(GRPC_LIB NAMES grpc)
|
||||
@@ -103,17 +96,12 @@ else()
|
||||
# that zlib will be very outdated
|
||||
set(ZLIB_INCLUDE "${GRPC_SRC}/third_party/zlib")
|
||||
set(ZLIB_LIB "${GRPC_LIBS_ABSOLUTE}/libz.a")
|
||||
# we tell gRPC to compile c-ares for us because when a gRPC package is not available, like on CentOS, it's very likely
|
||||
# that c-ares will be very outdated
|
||||
set(CARES_INCLUDE "${GRPC_SRC}/third_party/cares" "${GRPC_SRC}/third_party/cares/cares")
|
||||
set(CARES_LIB "${GRPC_LIBS_ABSOLUTE}/libares.a")
|
||||
|
||||
message(STATUS "Using bundled gRPC in '${GRPC_SRC}'")
|
||||
message(
|
||||
STATUS
|
||||
"Bundled gRPC comes with protobuf: compiler: ${PROTOC}, include: ${PROTOBUF_INCLUDE}, lib: ${PROTOBUF_LIB}")
|
||||
message(STATUS "Bundled gRPC comes with zlib: include: ${ZLIB_INCLUDE}, lib: ${ZLIB_LIB}}")
|
||||
message(STATUS "Bundled gRPC comes with cares: include: ${CARES_INCLUDE}, lib: ${CARES_LIB}}")
|
||||
message(STATUS "Bundled gRPC comes with gRPC C++ plugin: include: ${GRPC_CPP_PLUGIN}")
|
||||
|
||||
get_filename_component(PROTOC_DIR ${PROTOC} PATH)
|
||||
@@ -122,8 +110,8 @@ else()
|
||||
grpc
|
||||
DEPENDS openssl
|
||||
GIT_REPOSITORY https://github.com/grpc/grpc.git
|
||||
GIT_TAG v1.32.0
|
||||
GIT_SUBMODULES "third_party/protobuf third_party/zlib third_party/cares/cares third_party/abseil-cpp third_party/re2"
|
||||
GIT_TAG v1.25.0
|
||||
GIT_SUBMODULES "third_party/protobuf third_party/zlib third_party/cares/cares"
|
||||
BUILD_IN_SOURCE 1
|
||||
BUILD_BYPRODUCTS ${GRPC_LIB} ${GRPCPP_LIB}
|
||||
INSTALL_COMMAND ""
|
||||
@@ -133,8 +121,6 @@ else()
|
||||
HAS_SYSTEM_ZLIB=false
|
||||
HAS_SYSTEM_PROTOBUF=false
|
||||
HAS_SYSTEM_CARES=false
|
||||
HAS_EMBEDDED_OPENSSL_ALPN=false
|
||||
HAS_SYSTEM_OPENSSL_ALPN=true
|
||||
PKG_CONFIG_PATH=${OPENSSL_BUNDLE_DIR}
|
||||
PKG_CONFIG=${PKG_CONFIG_EXECUTABLE}
|
||||
PATH=${PROTOC_DIR}:$ENV{PATH}
|
||||
|
||||
@@ -10,45 +10,26 @@
|
||||
# "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.
|
||||
#
|
||||
mark_as_advanced(JQ_INCLUDE JQ_LIB)
|
||||
if (NOT USE_BUNDLED_DEPS)
|
||||
find_path(JQ_INCLUDE jq.h PATH_SUFFIXES jq)
|
||||
find_library(JQ_LIB NAMES jq)
|
||||
if (JQ_INCLUDE AND JQ_LIB)
|
||||
message(STATUS "Found jq: include: ${JQ_INCLUDE}, lib: ${JQ_LIB}")
|
||||
else ()
|
||||
message(FATAL_ERROR "Couldn't find system jq")
|
||||
endif ()
|
||||
else ()
|
||||
set(JQ_SRC "${PROJECT_BINARY_DIR}/jq-prefix/src/jq")
|
||||
message(STATUS "Using bundled jq in '${JQ_SRC}'")
|
||||
set(JQ_INCLUDE "${JQ_SRC}/target/include")
|
||||
set(JQ_INSTALL_DIR "${JQ_SRC}/target")
|
||||
set(JQ_LIB "${JQ_INSTALL_DIR}/lib/libjq.a")
|
||||
set(ONIGURUMA_LIB "${JQ_INSTALL_DIR}/lib/libonig.a")
|
||||
message(STATUS "Bundled jq: include: ${JQ_INCLUDE}, lib: ${JQ_LIB}")
|
||||
|
||||
# Why we mirror jq here?
|
||||
#
|
||||
# In their readme, jq claims that you don't have
|
||||
# to do autoreconf -fi when downloading a released tarball.
|
||||
#
|
||||
# However, they forgot to push the released makefiles
|
||||
# into their release tarbal.
|
||||
#
|
||||
# For this reason, we have to mirror their release after
|
||||
# doing the configuration ourselves.
|
||||
#
|
||||
# This is needed because many distros do not ship the right
|
||||
# version of autoreconf, making virtually impossible to build Falco on them.
|
||||
# Read more about it here:
|
||||
# https://github.com/stedolan/jq/issues/2061#issuecomment-593445920
|
||||
ExternalProject_Add(
|
||||
jq
|
||||
URL "https://dl.bintray.com/falcosecurity/dependencies/jq-1.6.tar.gz"
|
||||
URL_HASH "SHA256=787518068c35e244334cc79b8e56b60dbab352dff175b7f04a94f662b540bfd9"
|
||||
CONFIGURE_COMMAND ./configure --disable-maintainer-mode --enable-all-static --disable-dependency-tracking --with-oniguruma=builtin --prefix=${JQ_INSTALL_DIR}
|
||||
BUILD_COMMAND ${CMD_MAKE} LDFLAGS=-all-static
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND ${CMD_MAKE} install)
|
||||
endif ()
|
||||
if(NOT USE_BUNDLED_DEPS)
|
||||
find_path(JQ_INCLUDE jq.h PATH_SUFFIXES jq)
|
||||
find_library(JQ_LIB NAMES jq)
|
||||
if(JQ_INCLUDE AND JQ_LIB)
|
||||
message(STATUS "Found jq: include: ${JQ_INCLUDE}, lib: ${JQ_LIB}")
|
||||
else()
|
||||
message(FATAL_ERROR "Couldn't find system jq")
|
||||
endif()
|
||||
else()
|
||||
set(JQ_SRC "${PROJECT_BINARY_DIR}/jq-prefix/src/jq")
|
||||
message(STATUS "Using bundled jq in '${JQ_SRC}'")
|
||||
set(JQ_INCLUDE "${JQ_SRC}")
|
||||
set(JQ_LIB "${JQ_SRC}/.libs/libjq.a")
|
||||
ExternalProject_Add(
|
||||
jq
|
||||
URL "https://github.com/stedolan/jq/releases/download/jq-1.5/jq-1.5.tar.gz"
|
||||
URL_HASH "SHA256=c4d2bfec6436341113419debf479d833692cc5cdab7eb0326b5a4d4fbe9f493c"
|
||||
CONFIGURE_COMMAND ./configure --disable-maintainer-mode --enable-all-static --disable-dependency-tracking
|
||||
BUILD_COMMAND ${CMD_MAKE} LDFLAGS=-all-static
|
||||
BUILD_IN_SOURCE 1
|
||||
PATCH_COMMAND curl -L https://github.com/stedolan/jq/commit/8eb1367ca44e772963e704a700ef72ae2e12babd.patch | patch
|
||||
INSTALL_COMMAND "")
|
||||
endif()
|
||||
|
||||
@@ -10,18 +10,23 @@
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
#
|
||||
|
||||
set(LIBYAML_SRC "${PROJECT_BINARY_DIR}/libyaml-prefix/src/libyaml")
|
||||
set(LIBYAML_INSTALL_DIR "${LIBYAML_SRC}/target")
|
||||
message(STATUS "Using bundled libyaml in '${LIBYAML_SRC}'")
|
||||
set(LIBYAML_LIB "${LIBYAML_SRC}/src/.libs/libyaml.a")
|
||||
externalproject_add(
|
||||
libyaml
|
||||
URL "https://github.com/yaml/libyaml/releases/download/0.2.5/yaml-0.2.5.tar.gz"
|
||||
URL_HASH "SHA256=c642ae9b75fee120b2d96c712538bd2cf283228d2337df2cf2988e3c02678ef4"
|
||||
CONFIGURE_COMMAND ./configure --prefix=${LIBYAML_INSTALL_DIR} CFLAGS=-fPIC CPPFLAGS=-fPIC --enable-static=true --enable-shared=false
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
BUILD_BYPRODUCTS ${LIBYAML_LIB}
|
||||
INSTALL_COMMAND ${CMD_MAKE} install
|
||||
)
|
||||
if(NOT USE_BUNDLED_DEPS)
|
||||
find_library(LIBYAML_LIB NAMES libyaml.so)
|
||||
if(LIBYAML_LIB)
|
||||
message(STATUS "Found libyaml: lib: ${LIBYAML_LIB}")
|
||||
else()
|
||||
message(FATAL_ERROR "Couldn't find system libyaml")
|
||||
endif()
|
||||
else()
|
||||
set(LIBYAML_SRC "${PROJECT_BINARY_DIR}/libyaml-prefix/src/libyaml")
|
||||
message(STATUS "Using bundled libyaml in '${LIBYAML_SRC}'")
|
||||
set(LIBYAML_LIB "${LIBYAML_SRC}/src/.libs/libyaml.a")
|
||||
ExternalProject_Add(
|
||||
libyaml
|
||||
URL "https://github.com/yaml/libyaml/releases/download/0.2.5/yaml-0.2.5.tar.gz"
|
||||
URL_HASH "SHA256=c642ae9b75fee120b2d96c712538bd2cf283228d2337df2cf2988e3c02678ef4"
|
||||
CONFIGURE_COMMAND ./configure --enable-static=true --enable-shared=false
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND "")
|
||||
endif()
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
set(LPEG_SRC "${PROJECT_BINARY_DIR}/lpeg-prefix/src/lpeg")
|
||||
set(LPEG_LIB "${PROJECT_BINARY_DIR}/lpeg-prefix/src/lpeg/build/lpeg.a")
|
||||
message(STATUS "Using bundled lpeg in '${LPEG_SRC}'")
|
||||
set(LPEG_DEPENDENCIES "")
|
||||
list(APPEND LPEG_DEPENDENCIES "luajit")
|
||||
ExternalProject_Add(
|
||||
lpeg
|
||||
DEPENDS ${LPEG_DEPENDENCIES}
|
||||
URL "http://www.inf.puc-rio.br/~roberto/lpeg/lpeg-1.0.2.tar.gz"
|
||||
URL_HASH "SHA256=48d66576051b6c78388faad09b70493093264588fcd0f258ddaab1cdd4a15ffe"
|
||||
BUILD_COMMAND LUA_INCLUDE=${LUAJIT_INCLUDE} "${PROJECT_SOURCE_DIR}/scripts/build-lpeg.sh" "${LPEG_SRC}/build"
|
||||
BUILD_IN_SOURCE 1
|
||||
BUILD_BYPRODUCTS ${LPEG_LIB}
|
||||
CONFIGURE_COMMAND ""
|
||||
INSTALL_COMMAND "")
|
||||
@@ -1,27 +0,0 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
set(LUAJIT_SRC "${PROJECT_BINARY_DIR}/luajit-prefix/src/luajit/src")
|
||||
message(STATUS "Using bundled LuaJIT in '${LUAJIT_SRC}'")
|
||||
set(LUAJIT_INCLUDE "${LUAJIT_SRC}")
|
||||
set(LUAJIT_LIB "${LUAJIT_SRC}/libluajit.a")
|
||||
externalproject_add(
|
||||
luajit
|
||||
GIT_REPOSITORY "https://github.com/LuaJIT/LuaJIT"
|
||||
GIT_TAG "1d8b747c161db457e032a023ebbff511f5de5ec2"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
BUILD_BYPRODUCTS ${LUAJIT_LIB}
|
||||
INSTALL_COMMAND ""
|
||||
)
|
||||
@@ -1,28 +0,0 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
set(LYAML_SRC "${PROJECT_BINARY_DIR}/lyaml-prefix/src/lyaml/ext/yaml")
|
||||
set(LYAML_LIB "${LYAML_SRC}/.libs/yaml.a")
|
||||
message(STATUS "Using bundled lyaml in '${LYAML_SRC}'")
|
||||
externalproject_add(
|
||||
lyaml
|
||||
DEPENDS luajit libyaml
|
||||
URL "https://github.com/gvvaughan/lyaml/archive/release-v6.0.tar.gz"
|
||||
URL_HASH "SHA256=9d7cf74d776999ff6f758c569d5202ff5da1f303c6f4229d3b41f71cd3a3e7a7"
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
BUILD_BYPRODUCTS ${LYAML_LIB}
|
||||
CONFIGURE_COMMAND ./configure --enable-static CFLAGS=-I${LIBYAML_INSTALL_DIR}/include CPPFLAGS=-I${LIBYAML_INSTALL_DIR}/include LDFLAGS=-L${LIBYAML_INSTALL_DIR}/lib LIBS=-lyaml LUA=${LUAJIT_SRC}/luajit LUA_INCLUDE=-I${LUAJIT_INCLUDE}
|
||||
INSTALL_COMMAND sh -c
|
||||
"cp -R ${PROJECT_BINARY_DIR}/lyaml-prefix/src/lyaml/lib/* ${PROJECT_SOURCE_DIR}/userspace/engine/lua"
|
||||
)
|
||||
@@ -1,43 +0,0 @@
|
||||
# create the reports folder
|
||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/static-analysis-reports)
|
||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/static-analysis-reports/cppcheck)
|
||||
|
||||
# cppcheck
|
||||
mark_as_advanced(CPPCHECK CPPCHECK_HTMLREPORT)
|
||||
find_program(CPPCHECK cppcheck)
|
||||
find_program(CPPCHECK_HTMLREPORT cppcheck-htmlreport)
|
||||
|
||||
if(NOT CPPCHECK)
|
||||
message(STATUS "cppcheck command not found, static code analysis using cppcheck will not be available.")
|
||||
else()
|
||||
message(STATUS "cppcheck found at: ${CPPCHECK}")
|
||||
# we are aware that cppcheck can be run
|
||||
# along with the software compilation in a single step
|
||||
# using the CMAKE_CXX_CPPCHECK variables.
|
||||
# However, for practical needs we want to keep the
|
||||
# two things separated and have a specific target for it.
|
||||
# Our cppcheck target reads the compilation database produced by CMake
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS On)
|
||||
add_custom_target(
|
||||
cppcheck
|
||||
COMMAND ${CPPCHECK}
|
||||
"--enable=all"
|
||||
"--force"
|
||||
"--inconclusive"
|
||||
"--inline-suppr" # allows to specify suppressions directly in source code
|
||||
"--project=${CMAKE_CURRENT_BINARY_DIR}/compile_commands.json" # use the compilation database as source
|
||||
"--quiet"
|
||||
"--xml" # we want to generate a report
|
||||
"--output-file=${CMAKE_CURRENT_BINARY_DIR}/static-analysis-reports/cppcheck/cppcheck.xml" # generate the report under the reports folder in the build folder
|
||||
"-i${CMAKE_CURRENT_BINARY_DIR}"# exclude the build folder
|
||||
)
|
||||
endif() # CPPCHECK
|
||||
|
||||
if(NOT CPPCHECK_HTMLREPORT)
|
||||
message(STATUS "cppcheck-htmlreport command not found, will not be able to produce html reports for cppcheck results")
|
||||
else()
|
||||
message(STATUS "cppcheck-htmlreport found at: ${CPPCHECK_HTMLREPORT}")
|
||||
add_custom_target(
|
||||
cppcheck_htmlreport
|
||||
COMMAND ${CPPCHECK_HTMLREPORT} --title=${CMAKE_PROJECT_NAME} --report-dir=${CMAKE_CURRENT_BINARY_DIR}/static-analysis-reports/cppcheck --file=static-analysis-reports/cppcheck/cppcheck.xml)
|
||||
endif() # CPPCHECK_HTMLREPORT
|
||||
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
# Copyright (C) 2019 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
|
||||
@@ -25,4 +25,4 @@ ExternalProject_Add(
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
PATCH_COMMAND patch -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/patch/libscap.patch && patch -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/patch/luajit.patch)
|
||||
PATCH_COMMAND patch -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/patch/libscap.patch)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
diff --git a/userspace/libscap/scap.c b/userspace/libscap/scap.c
|
||||
index 6f51588e..5f9ea84e 100644
|
||||
index e9faea51..a1b3b501 100644
|
||||
--- a/userspace/libscap/scap.c
|
||||
+++ b/userspace/libscap/scap.c
|
||||
@@ -55,7 +55,7 @@ limitations under the License.
|
||||
@@ -52,7 +52,7 @@ limitations under the License.
|
||||
//#define NDEBUG
|
||||
#include <assert.h>
|
||||
|
||||
@@ -11,16 +11,7 @@ index 6f51588e..5f9ea84e 100644
|
||||
|
||||
//
|
||||
// Probe version string size
|
||||
@@ -114,7 +114,7 @@ scap_t* scap_open_udig_int(char *error, int32_t *rc,
|
||||
static uint32_t get_max_consumers()
|
||||
{
|
||||
uint32_t max;
|
||||
- FILE *pfile = fopen("/sys/module/" PROBE_DEVICE_NAME "_probe/parameters/max_consumers", "r");
|
||||
+ FILE *pfile = fopen("/sys/module/" PROBE_DEVICE_NAME "/parameters/max_consumers", "r");
|
||||
if(pfile != NULL)
|
||||
{
|
||||
int w = fscanf(pfile, "%"PRIu32, &max);
|
||||
@@ -186,7 +186,7 @@ scap_t* scap_open_live_int(char *error, int32_t *rc,
|
||||
@@ -171,7 +171,7 @@ scap_t* scap_open_live_int(char *error, int32_t *rc,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -29,27 +20,7 @@ index 6f51588e..5f9ea84e 100644
|
||||
bpf_probe = buf;
|
||||
}
|
||||
}
|
||||
@@ -344,7 +344,7 @@ scap_t* scap_open_live_int(char *error, int32_t *rc,
|
||||
else if(errno == EBUSY)
|
||||
{
|
||||
uint32_t curr_max_consumers = get_max_consumers();
|
||||
- snprintf(error, SCAP_LASTERR_SIZE, "Too many sysdig instances attached to device %s. Current value for /sys/module/" PROBE_DEVICE_NAME "_probe/parameters/max_consumers is '%"PRIu32"'.", filename, curr_max_consumers);
|
||||
+ snprintf(error, SCAP_LASTERR_SIZE, "Too many Falco instances attached to device %s. Current value for /sys/module/" PROBE_DEVICE_NAME "/parameters/max_consumers is '%"PRIu32"'.", filename, curr_max_consumers);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -579,8 +579,8 @@ scap_t* scap_open_udig_int(char *error, int32_t *rc,
|
||||
//
|
||||
// Map the ppm_ring_buffer_info that contains the buffer pointers
|
||||
//
|
||||
- if(udig_alloc_ring_descriptors(&(handle->m_devs[0].m_bufinfo_fd),
|
||||
- &handle->m_devs[0].m_bufinfo,
|
||||
+ if(udig_alloc_ring_descriptors(&(handle->m_devs[0].m_bufinfo_fd),
|
||||
+ &handle->m_devs[0].m_bufinfo,
|
||||
&handle->m_devs[0].m_bufstatus,
|
||||
error) != SCAP_SUCCESS)
|
||||
{
|
||||
@@ -2175,7 +2175,7 @@ int32_t scap_disable_dynamic_snaplen(scap_t* handle)
|
||||
@@ -1808,7 +1808,7 @@ int32_t scap_disable_dynamic_snaplen(scap_t* handle)
|
||||
|
||||
const char* scap_get_host_root()
|
||||
{
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
diff --git a/userspace/libsinsp/chisel.cpp b/userspace/libsinsp/chisel.cpp
|
||||
index 0a6e3cf8..0c2e255a 100644
|
||||
--- a/userspace/libsinsp/chisel.cpp
|
||||
+++ b/userspace/libsinsp/chisel.cpp
|
||||
@@ -98,7 +98,7 @@ void lua_stackdump(lua_State *L)
|
||||
// Lua callbacks
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#ifdef HAS_LUA_CHISELS
|
||||
-const static struct luaL_reg ll_sysdig [] =
|
||||
+const static struct luaL_Reg ll_sysdig [] =
|
||||
{
|
||||
{"set_filter", &lua_cbacks::set_global_filter},
|
||||
{"set_snaplen", &lua_cbacks::set_snaplen},
|
||||
@@ -134,7 +134,7 @@ const static struct luaL_reg ll_sysdig [] =
|
||||
{NULL,NULL}
|
||||
};
|
||||
|
||||
-const static struct luaL_reg ll_chisel [] =
|
||||
+const static struct luaL_Reg ll_chisel [] =
|
||||
{
|
||||
{"request_field", &lua_cbacks::request_field},
|
||||
{"set_filter", &lua_cbacks::set_filter},
|
||||
@@ -146,7 +146,7 @@ const static struct luaL_reg ll_chisel [] =
|
||||
{NULL,NULL}
|
||||
};
|
||||
|
||||
-const static struct luaL_reg ll_evt [] =
|
||||
+const static struct luaL_Reg ll_evt [] =
|
||||
{
|
||||
{"field", &lua_cbacks::field},
|
||||
{"get_num", &lua_cbacks::get_num},
|
||||
diff --git a/userspace/libsinsp/lua_parser.cpp b/userspace/libsinsp/lua_parser.cpp
|
||||
index 0e26617d..78810d96 100644
|
||||
--- a/userspace/libsinsp/lua_parser.cpp
|
||||
+++ b/userspace/libsinsp/lua_parser.cpp
|
||||
@@ -32,7 +32,7 @@ extern "C" {
|
||||
#include "lauxlib.h"
|
||||
}
|
||||
|
||||
-const static struct luaL_reg ll_filter [] =
|
||||
+const static struct luaL_Reg ll_filter [] =
|
||||
{
|
||||
{"rel_expr", &lua_parser_cbacks::rel_expr},
|
||||
{"bool_op", &lua_parser_cbacks::bool_op},
|
||||
diff --git a/userspace/libsinsp/lua_parser_api.cpp b/userspace/libsinsp/lua_parser_api.cpp
|
||||
index c89e9126..c3d8008a 100644
|
||||
--- a/userspace/libsinsp/lua_parser_api.cpp
|
||||
+++ b/userspace/libsinsp/lua_parser_api.cpp
|
||||
@@ -266,7 +266,7 @@ int lua_parser_cbacks::rel_expr(lua_State *ls)
|
||||
string err = "Got non-table as in-expression operand\n";
|
||||
throw sinsp_exception("parser API error");
|
||||
}
|
||||
- int n = luaL_getn(ls, 4); /* get size of table */
|
||||
+ int n = lua_objlen (ls, 4); /* get size of table */
|
||||
for (i=1; i<=n; i++)
|
||||
{
|
||||
lua_rawgeti(ls, 4, i);
|
||||
@@ -17,26 +17,23 @@ set(SYSDIG_CMAKE_WORKING_DIR "${CMAKE_BINARY_DIR}/sysdig-repo")
|
||||
# this needs to be here at the top
|
||||
if(USE_BUNDLED_DEPS)
|
||||
# explicitly force this dependency to use the bundled OpenSSL
|
||||
if(NOT MINIMAL_BUILD)
|
||||
set(USE_BUNDLED_OPENSSL ON)
|
||||
endif()
|
||||
set(USE_BUNDLED_JQ ON)
|
||||
set(USE_BUNDLED_OPENSSL ON)
|
||||
endif()
|
||||
|
||||
file(MAKE_DIRECTORY ${SYSDIG_CMAKE_WORKING_DIR})
|
||||
|
||||
# The sysdig git reference (branch name, commit hash, or tag) To update sysdig version for the next release, change the
|
||||
# default below In case you want to test against another sysdig version just pass the variable - ie., `cmake
|
||||
# -DSYSDIG_VERSION=dev ..`
|
||||
# The sysdig git reference (branch name, commit hash, or tag)
|
||||
# To update sysdig version for the next release, change the default below
|
||||
# In case you want to test against another sysdig version just pass the variable - ie., `cmake -DSYSDIG_VERSION=dev ..`
|
||||
if(NOT SYSDIG_VERSION)
|
||||
set(SYSDIG_VERSION "5c0b863ddade7a45568c0ac97d037422c9efb750")
|
||||
set(SYSDIG_CHECKSUM "SHA256=9de717b3a4b611ea6df56afee05171860167112f74bb7717b394bcc88ac843cd")
|
||||
set(SYSDIG_VERSION "85c88952b018fdbce2464222c3303229f5bfcfad")
|
||||
set(SYSDIG_CHECKSUM "SHA256=6c3f5f2d699c9540e281f50cbc5cb6b580f0fc689798bc65d4a77f57f932a71c")
|
||||
endif()
|
||||
set(PROBE_VERSION "${SYSDIG_VERSION}")
|
||||
|
||||
# cd /path/to/build && cmake /path/to/source
|
||||
execute_process(COMMAND "${CMAKE_COMMAND}" -DSYSDIG_VERSION=${SYSDIG_VERSION} -DSYSDIG_CHECKSUM=${SYSDIG_CHECKSUM}
|
||||
${SYSDIG_CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${SYSDIG_CMAKE_WORKING_DIR})
|
||||
execute_process(COMMAND "${CMAKE_COMMAND}" -DSYSDIG_VERSION=${SYSDIG_VERSION} -DSYSDIG_CHECKSUM=${SYSDIG_CHECKSUM} ${SYSDIG_CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${SYSDIG_CMAKE_WORKING_DIR})
|
||||
|
||||
|
||||
# todo(leodido, fntlnz) > use the following one when CMake version will be >= 3.13
|
||||
|
||||
@@ -57,10 +54,6 @@ add_subdirectory("${SYSDIG_SOURCE_DIR}/driver" "${PROJECT_BINARY_DIR}/driver")
|
||||
# Add libscap directory
|
||||
add_definitions(-D_GNU_SOURCE)
|
||||
add_definitions(-DHAS_CAPTURE)
|
||||
add_definitions(-DNOCURSESUI)
|
||||
if(MUSL_OPTIMIZED_BUILD)
|
||||
add_definitions(-DMUSL_OPTIMIZED)
|
||||
endif()
|
||||
add_subdirectory("${SYSDIG_SOURCE_DIR}/userspace/libscap" "${PROJECT_BINARY_DIR}/userspace/libscap")
|
||||
|
||||
# Add libsinsp directory
|
||||
@@ -71,8 +64,5 @@ add_dependencies(sinsp tbb b64 luajit)
|
||||
set(CREATE_TEST_TARGETS OFF)
|
||||
|
||||
if(USE_BUNDLED_DEPS)
|
||||
add_dependencies(scap jq)
|
||||
if(NOT MINIMAL_BUILD)
|
||||
add_dependencies(scap curl grpc)
|
||||
endif()
|
||||
add_dependencies(scap grpc curl jq)
|
||||
endif()
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
# "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.
|
||||
#
|
||||
mark_as_advanced(YAMLCPP_INCLUDE_DIR YAMLCPP_LIB)
|
||||
if(NOT USE_BUNDLED_DEPS)
|
||||
find_path(YAMLCPP_INCLUDE_DIR NAMES yaml-cpp/yaml.h)
|
||||
find_library(YAMLCPP_LIB NAMES yaml-cpp)
|
||||
|
||||
@@ -34,7 +34,6 @@ case "$CMD" in
|
||||
-DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||
-DBUILD_DRIVER="$BUILD_DRIVER" \
|
||||
-DMINIMAL_BUILD="$MINIMAL_BUILD" \
|
||||
-DBUILD_BPF="$BUILD_BPF" \
|
||||
-DBUILD_WARNINGS_AS_ERRORS="$BUILD_WARNINGS_AS_ERRORS" \
|
||||
-DFALCO_VERSION="$FALCO_VERSION" \
|
||||
|
||||
@@ -3,7 +3,7 @@ FROM falcosecurity/falco:${FALCO_IMAGE_TAG}
|
||||
|
||||
LABEL maintainer="cncf-falco-dev@lists.cncf.io"
|
||||
|
||||
LABEL usage="docker run -i -t --privileged -v /root/.falco:/root/.falco -v /proc:/host/proc:ro -v /boot:/host/boot:ro -v /lib/modules:/host/lib/modules:ro -v /usr:/host/usr:ro -v /etc:/host/etc:ro --name NAME IMAGE"
|
||||
LABEL usage="docker run -i -t -v /dev:/host/dev -v /proc:/host/proc:ro -v /boot:/host/boot:ro -v /lib/modules:/host/lib/modules:ro -v /usr:/host/usr:ro --name NAME IMAGE"
|
||||
|
||||
ENV HOST_ROOT /host
|
||||
ENV HOME /root
|
||||
|
||||
@@ -2,7 +2,7 @@ FROM debian:stable
|
||||
|
||||
LABEL maintainer="cncf-falco-dev@lists.cncf.io"
|
||||
|
||||
LABEL usage="docker run -i -t --privileged -v /var/run/docker.sock:/host/var/run/docker.sock -v /dev:/host/dev -v /proc:/host/proc:ro -v /boot:/host/boot:ro -v /lib/modules:/host/lib/modules:ro -v /usr:/host/usr:ro -v /etc:/host/etc --name NAME IMAGE"
|
||||
LABEL usage="docker run -i -t -v /var/run/docker.sock:/host/var/run/docker.sock -v /dev:/host/dev -v /proc:/host/proc:ro -v /boot:/host/boot:ro -v /lib/modules:/host/lib/modules:ro -v /usr:/host/usr:ro --name NAME IMAGE"
|
||||
|
||||
ARG FALCO_VERSION=latest
|
||||
ARG VERSION_BUCKET=deb
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
FROM ubuntu:18.04 as ubuntu
|
||||
|
||||
LABEL maintainer="cncf-falco-dev@lists.cncf.io"
|
||||
|
||||
ARG FALCO_VERSION
|
||||
ARG VERSION_BUCKET=bin
|
||||
|
||||
@@ -10,23 +12,46 @@ WORKDIR /
|
||||
|
||||
ADD https://bintray.com/api/ui/download/falcosecurity/${VERSION_BUCKET}/x86_64/falco-${FALCO_VERSION}-x86_64.tar.gz /
|
||||
|
||||
RUN tar -xvf falco-${FALCO_VERSION}-x86_64.tar.gz && \
|
||||
RUN apt-get update -y && \
|
||||
apt-get install -y binutils && \
|
||||
tar -xvf falco-${FALCO_VERSION}-x86_64.tar.gz && \
|
||||
rm -f falco-${FALCO_VERSION}-x86_64.tar.gz && \
|
||||
mv falco-${FALCO_VERSION}-x86_64 falco && \
|
||||
rm -rf falco/usr/src/falco-* falco/usr/bin/falco-driver-loader
|
||||
strip falco/usr/bin/falco && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
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 scratch
|
||||
|
||||
LABEL maintainer="cncf-falco-dev@lists.cncf.io"
|
||||
COPY --from=ubuntu /lib/x86_64-linux-gnu/libanl.so.1 \
|
||||
/lib/x86_64-linux-gnu/libc.so.6 \
|
||||
/lib/x86_64-linux-gnu/libdl.so.2 \
|
||||
/lib/x86_64-linux-gnu/libgcc_s.so.1 \
|
||||
/lib/x86_64-linux-gnu/libm.so.6 \
|
||||
/lib/x86_64-linux-gnu/libnsl.so.1 \
|
||||
/lib/x86_64-linux-gnu/libnss_compat.so.2 \
|
||||
/lib/x86_64-linux-gnu/libnss_files.so.2 \
|
||||
/lib/x86_64-linux-gnu/libnss_nis.so.2 \
|
||||
/lib/x86_64-linux-gnu/libpthread.so.0 \
|
||||
/lib/x86_64-linux-gnu/librt.so.1 \
|
||||
/lib/x86_64-linux-gnu/libz.so.1 \
|
||||
/lib/x86_64-linux-gnu/
|
||||
|
||||
LABEL usage="docker run -i -t --privileged -v /var/run/docker.sock:/host/var/run/docker.sock -v /dev:/host/dev -v /proc:/host/proc:ro --name NAME IMAGE"
|
||||
# NOTE: for the "least privileged" use case, please refer to the official documentation
|
||||
COPY --from=ubuntu /usr/lib/x86_64-linux-gnu/libstdc++.so.6 \
|
||||
/usr/lib/x86_64-linux-gnu/libstdc++.so.6
|
||||
|
||||
ENV HOST_ROOT /host
|
||||
ENV HOME /root
|
||||
COPY --from=ubuntu /etc/ld.so.cache \
|
||||
/etc/nsswitch.conf \
|
||||
/etc/ld.so.cache \
|
||||
/etc/passwd \
|
||||
/etc/group \
|
||||
/etc/
|
||||
|
||||
COPY --from=ubuntu /etc/default/nss /etc/default/nss
|
||||
COPY --from=ubuntu /lib64/ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2
|
||||
|
||||
COPY --from=ubuntu /falco /
|
||||
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
BUILD_DIR=${BUILD_DIR:-/build}
|
||||
SOURCE_DIR=${SOURCE_DIR:-/source}
|
||||
SKIP_PACKAGES_TESTS=${SKIP_PACKAGES_TESTS:-false}
|
||||
set -eu -o pipefail
|
||||
|
||||
SOURCE_DIR=/source
|
||||
BUILD_DIR=/build
|
||||
CMD=${1:-test}
|
||||
shift
|
||||
|
||||
# Stop the execution if a command in the pipeline has an error, from now on
|
||||
set -e -u -o pipefail
|
||||
|
||||
# build type can be "debug" or "release", fallbacks to "release" by default
|
||||
BUILD_TYPE=$(echo "$BUILD_TYPE" | tr "[:upper:]" "[:lower:]")
|
||||
case "$BUILD_TYPE" in
|
||||
@@ -50,8 +47,7 @@ case "$CMD" in
|
||||
"test")
|
||||
if [ -z "$FALCO_VERSION" ]; then
|
||||
echo "Automatically figuring out Falco version."
|
||||
FALCO_VERSION_FULL=$("$BUILD_DIR/$BUILD_TYPE/userspace/falco/falco" --version)
|
||||
FALCO_VERSION=$(echo "$FALCO_VERSION_FULL" | head -n 1 | cut -d' ' -f3 | tr -d '\r')
|
||||
FALCO_VERSION=$("$BUILD_DIR/$BUILD_TYPE/userspace/falco/falco" --version | head -n 1 | cut -d' ' -f3 | tr -d '\r')
|
||||
echo "Falco version: $FALCO_VERSION"
|
||||
fi
|
||||
if [ -z "$FALCO_VERSION" ]; then
|
||||
@@ -60,11 +56,9 @@ case "$CMD" in
|
||||
fi
|
||||
|
||||
# build docker images
|
||||
if [ "$SKIP_PACKAGES_TESTS" = false ] ; then
|
||||
build_image "$BUILD_DIR" "$BUILD_TYPE" "$FALCO_VERSION" "deb"
|
||||
build_image "$BUILD_DIR" "$BUILD_TYPE" "$FALCO_VERSION" "rpm"
|
||||
build_image "$BUILD_DIR" "$BUILD_TYPE" "$FALCO_VERSION" "tar.gz"
|
||||
fi
|
||||
build_image "$BUILD_DIR" "$BUILD_TYPE" "$FALCO_VERSION" "deb"
|
||||
build_image "$BUILD_DIR" "$BUILD_TYPE" "$FALCO_VERSION" "rpm"
|
||||
build_image "$BUILD_DIR" "$BUILD_TYPE" "$FALCO_VERSION" "tar.gz"
|
||||
|
||||
# check that source directory contains Falco
|
||||
if [ ! -d "$SOURCE_DIR/falco/test" ]; then
|
||||
@@ -75,14 +69,12 @@ case "$CMD" in
|
||||
# run tests
|
||||
echo "Running regression tests ..."
|
||||
cd "$SOURCE_DIR/falco/test"
|
||||
SKIP_PACKAGES_TESTS=$SKIP_PACKAGES_TESTS ./run_regression_tests.sh -d "$BUILD_DIR/$BUILD_TYPE"
|
||||
./run_regression_tests.sh -d "$BUILD_DIR/$BUILD_TYPE"
|
||||
|
||||
# clean docker images
|
||||
if [ "$SKIP_PACKAGES_TESTS" = false ] ; then
|
||||
clean_image "deb"
|
||||
clean_image "rpm"
|
||||
clean_image "tar.gz"
|
||||
fi
|
||||
clean_image "deb"
|
||||
clean_image "rpm"
|
||||
clean_image "tar.gz"
|
||||
;;
|
||||
"bash")
|
||||
CMD=/bin/bash
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(FalcoDocs)
|
||||
|
||||
# Dependencies
|
||||
|
||||
include(../cmake/modules/CPM.cmake)
|
||||
|
||||
CPMAddPackage(NAME Falco SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/..)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME MCSS
|
||||
DOWNLOAD_ONLY YES
|
||||
GITHUB_REPOSITORY mosra/m.css
|
||||
GIT_TAG 42d4a9a48f31f5df6e246c948403b54b50574a2a
|
||||
)
|
||||
|
||||
# Doxygen variables
|
||||
|
||||
set(DOXYGEN_PROJECT_NAME Falco)
|
||||
set(DOXYGEN_PROJECT_VERSION ${FALCO_VERSION})
|
||||
set(DOXYGEN_PROJECT_ROOT "${CMAKE_CURRENT_LIST_DIR}/..")
|
||||
set(DOXYGEN_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/doxygen")
|
||||
|
||||
configure_file(${CMAKE_CURRENT_LIST_DIR}/Doxyfile ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
|
||||
|
||||
configure_file(${CMAKE_CURRENT_LIST_DIR}/conf.py ${CMAKE_CURRENT_BINARY_DIR}/conf.py)
|
||||
|
||||
add_custom_target(
|
||||
GenerateDocs
|
||||
${CMAKE_COMMAND} -E make_directory "${DOXYGEN_OUTPUT_DIRECTORY}"
|
||||
COMMAND "${MCSS_SOURCE_DIR}/documentation/doxygen.py" "${CMAKE_CURRENT_BINARY_DIR}/conf.py"
|
||||
COMMAND echo "Docs written to: ${DOXYGEN_OUTPUT_DIRECTORY}"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
@@ -1,31 +0,0 @@
|
||||
# Configuration for Doxygen for use with CMake
|
||||
# Only options that deviate from the default are included
|
||||
# To create a new Doxyfile containing all available options, call `doxygen -g`
|
||||
|
||||
# Get Project name and version from CMake
|
||||
PROJECT_NAME = @DOXYGEN_PROJECT_NAME@
|
||||
PROJECT_NUMBER = @DOXYGEN_PROJECT_VERSION@
|
||||
|
||||
# Add sources
|
||||
INPUT = @DOXYGEN_PROJECT_ROOT@/README.md @DOXYGEN_PROJECT_ROOT@/userspace @DOXYGEN_PROJECT_ROOT@/documentation/pages
|
||||
EXTRACT_ALL = YES
|
||||
RECURSIVE = YES
|
||||
OUTPUT_DIRECTORY = @DOXYGEN_OUTPUT_DIRECTORY@
|
||||
|
||||
# Use the README as a main page
|
||||
USE_MDFILE_AS_MAINPAGE = @DOXYGEN_PROJECT_ROOT@/README.md
|
||||
|
||||
# Set relative include paths
|
||||
FULL_PATH_NAMES = YES
|
||||
STRIP_FROM_PATH = @DOXYGEN_PROJECT_ROOT@/userspace @DOXYGEN_PROJECT_ROOT@
|
||||
|
||||
# We only need XML output because use m.css to generate the html documentation
|
||||
GENERATE_XML = YES
|
||||
GENERATE_HTML = NO
|
||||
GENERATE_LATEX = NO
|
||||
XML_PROGRAMLISTING = NO
|
||||
CREATE_SUBDIRS = NO
|
||||
|
||||
# Include all directories, files and namespaces in the documentation
|
||||
# Disable to include only explicitly documented objects
|
||||
M_SHOW_UNDOCUMENTED = YES
|
||||
@@ -1,19 +0,0 @@
|
||||
DOXYFILE = 'Doxyfile'
|
||||
|
||||
LINKS_NAVBAR1 = [
|
||||
(None, 'pages', [(None, 'about')]),
|
||||
(None, 'namespaces', []),
|
||||
]
|
||||
|
||||
# Add your own navbar links using the code below.
|
||||
# To find the valid link names, you can inspect the URL of a generated documentation site.
|
||||
|
||||
# LINKS_NAVBAR1 = [
|
||||
# (None, 'pages', [(None, 'about')]),
|
||||
# (None, 'namespaces', [(None, 'namespacexyz')]),
|
||||
# ]
|
||||
#
|
||||
# LINKS_NAVBAR2 = [
|
||||
# (None, 'annotated', [(None, 'classxyz_1_1_xyz')]),
|
||||
# (None, 'files', [(None, 'xyz_8h')]),
|
||||
# ]
|
||||
@@ -1,4 +0,0 @@
|
||||
/** @page about About
|
||||
@section doc Falco Documentation
|
||||
This is the documentation for the Falco project.
|
||||
*/
|
||||
17
falco.yaml
17
falco.yaml
@@ -87,23 +87,6 @@ syscall_event_drops:
|
||||
rate: .03333
|
||||
max_burst: 10
|
||||
|
||||
# Falco continuously monitors outputs performance. When an output channel does not allow
|
||||
# to deliver an alert within a given deadline, an error is reported indicating
|
||||
# which output is blocking notifications.
|
||||
# The timeout error will be reported to the log according to the above log_* settings.
|
||||
# Note that the notification will not be discarded from the output queue; thus,
|
||||
# output channels may indefinitely remain blocked.
|
||||
# An output timeout error indeed indicate a misconfiguration issue or I/O problems
|
||||
# that cannot be recovered by Falco and should be fixed by the user.
|
||||
#
|
||||
# The "output_timeout" value specifies the duration in milliseconds to wait before
|
||||
# considering the deadline exceed.
|
||||
#
|
||||
# With a 2000ms default, the notification consumer can block the Falco output
|
||||
# for up to 2 seconds without reaching the timeout.
|
||||
|
||||
output_timeout: 2000
|
||||
|
||||
# A throttling mechanism implemented as a token bucket limits the
|
||||
# rate of falco notifications. This throttling is controlled by the following configuration
|
||||
# options:
|
||||
|
||||
@@ -4,7 +4,7 @@ The **Falco Artifact Scope** proposal is divided in two parts:
|
||||
1. the Part 1 - *this document*: the State of Art of Falco artifacts
|
||||
2. the [Part 2](./20200506-artifacts-scope-part-2.md): the intended state moving forward
|
||||
|
||||
## Summary
|
||||
## Summary
|
||||
|
||||
As a project we would like to support the following artifacts.
|
||||
|
||||
@@ -16,7 +16,7 @@ Inspired by many previous issues and many of the weekly community calls.
|
||||
|
||||
## Terms
|
||||
|
||||
**falco**
|
||||
**falco**
|
||||
|
||||
*The Falco binary*
|
||||
|
||||
@@ -30,12 +30,12 @@ Inspired by many previous issues and many of the weekly community calls.
|
||||
|
||||
**package**
|
||||
|
||||
*An installable artifact that is operating system specific. All packages MUST be hosted on [bintray](https://bintray.com/falcosecurity).*
|
||||
*An installable artifact that is operating system specific. All packages MUST be hosted on bintray.*
|
||||
|
||||
**image**
|
||||
|
||||
*OCI compliant container image hosted on dockerhub with tags for every release and the current master branch.*
|
||||
|
||||
|
||||
|
||||
# Packages
|
||||
|
||||
@@ -52,11 +52,11 @@ List of currently official container images (for X86 64bits only):
|
||||
|
||||
| Name | Directory | Description |
|
||||
|---|---|---|
|
||||
| [falcosecurity/falco:latest](https://hub.docker.com/repository/docker/falcosecurity/falco), [falcosecurity/falco:_tag_](https://hub.docker.com/repository/docker/falcosecurity/falco), [falcosecurity/falco:master](https://hub.docker.com/repository/docker/falcosecurity/falco) | docker/stable | Falco (DEB built from git tag or from the master) with all the building toolchain. |
|
||||
| [falcosecurity/falco:latest-slim](https://hub.docker.com/repository/docker/falcosecurity/falco), [falcosecurity/falco:_tag_-slim](https://hub.docker.com/repository/docker/falcosecurity/falco),[falcosecurity/falco:master-slim](https://hub.docker.com/repository/docker/falcosecurity/falco) | docker/slim | Falco (DEB build from git tag or from the master) without the building toolchain. |
|
||||
| [falcosecurity/falco-driver-loader:latest](https://hub.docker.com/repository/docker/falcosecurity/falco-driver-loader), [falcosecurity/falco-driver-loader:_tag_](https://hub.docker.com/repository/docker/falcosecurity/falco-driver-loader), [falcosecurity/falco-driver-loader:master](https://hub.docker.com/repository/docker/falcosecurity/falco-driver-loader) | docker/driver-loader | `falco-driver-loader` as entrypoint with the building toolchain. |
|
||||
| [falcosecurity/falco-builder:latest](https://hub.docker.com/repository/docker/falcosecurity/falco-builder) | docker/builder | The complete build tool chain for compiling Falco from source. See [the documentation](https://falco.org/docs/source/) for more details on building from source. Used to build Falco (CI). |
|
||||
| [falcosecurity/falco-tester:latest](https://hub.docker.com/repository/docker/falcosecurity/falco-tester) | docker/tester | Container image for running the Falco test suite. Used to run Falco integration tests (CI). |
|
||||
| [falcosecurity/falco:latest](https://hub.docker.com/repository/docker/falcosecurity/falco), [falcosecurity/falco:_tag_](https://hub.docker.com/repository/docker/falcosecurity/falco), [falcosecurity/falco:master](https://hub.docker.com/repository/docker/falcosecurity/falco) | docker/stable | Falco (DEB built from git tag or from the master) with all the building toolchain. |
|
||||
| [falcosecurity/falco:latest-slim](https://hub.docker.com/repository/docker/falcosecurity/falco), [falcosecurity/falco:_tag_-slim](https://hub.docker.com/repository/docker/falcosecurity/falco),[falcosecurity/falco:master-slim](https://hub.docker.com/repository/docker/falcosecurity/falco) | docker/slim | Falco (DEB build from git tag or from the master) without the building toolchain. |
|
||||
| [falcosecurity/falco-driver-loader:latest](https://hub.docker.com/repository/docker/falcosecurity/falco-driver-loader), [falcosecurity/falco-driver-loader:_tag_](https://hub.docker.com/repository/docker/falcosecurity/falco-driver-loader), [falcosecurity/falco-driver-loader:master](https://hub.docker.com/repository/docker/falcosecurity/falco-driver-loader) | docker/driver-loader | `falco-driver-loader` as entrypoint with the building toolchain. |
|
||||
| [falcosecurity/falco-builder:latest](https://hub.docker.com/repository/docker/falcosecurity/falco-builder) | docker/builder | The complete build tool chain for compiling Falco from source. See [the documentation](https://falco.org/docs/source/) for more details on building from source. Used to build Falco (CI). |
|
||||
| [falcosecurity/falco-tester:latest](https://hub.docker.com/repository/docker/falcosecurity/falco-tester) | docker/tester | Container image for running the Falco test suite. Used to run Falco integration tests (CI). |
|
||||
| _to not be published_ | docker/local | Built on-the-fly and used by falco-tester. |
|
||||
|
||||
**Note**: `falco-builder`, `falco-tester` (and the `docker/local` image which it's built on the fly by the `falco-tester` one) are not integrated into the release process because they are development and CI tools that need to be manually pushed only when updated.
|
||||
@@ -76,7 +76,7 @@ This new [contrib](https://github.com/falcosecurity/contrib) repository will be
|
||||
|
||||
### repository
|
||||
|
||||
"_Incubating level_" projects such as [falco-exporter](https://github.com/falco-exporter) can be promoted from `contrib` to their own repository.
|
||||
"_Incubating level_" projects such as [falco-exporter](https://github.com/falco-exporter) can be promoted from `contrib` to their own repository.
|
||||
|
||||
This is done as needed, and can best be measured by the need to cut a release and use the GitHub release features. Again, this is at the discretion of the Falco open source community.
|
||||
|
||||
@@ -92,7 +92,7 @@ The *Part 1* is mainly intended as a cleanup process.
|
||||
For each item not listed above, ask if it needs to be moved or deleted.
|
||||
After the cleanup process, all items will match the *Part 1* of this proposal.
|
||||
|
||||
|
||||
|
||||
### Action Items
|
||||
|
||||
Here are SOME of the items that would need to be done, for example:
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
# Falco Artifacts Storage
|
||||
|
||||
This document reflects the way we store the Falco artifacts.
|
||||
|
||||
## Terms & Definitions
|
||||
|
||||
- [Falco artifacts](./20200506-artifacts-scope-part-1.md)
|
||||
- Bintray: artifacts distribution platform
|
||||
|
||||
## Packages
|
||||
|
||||
The Falco packages are **automatically** built and sent to [bintray](https://bintray.com/falcosecurity) in the following cases:
|
||||
|
||||
- a pull request gets merged into the master branch (**Falco development releases**)
|
||||
- a new Falco release (git tag) happens on the master branch (**Falco stable releases**)
|
||||
|
||||
The only prerequisite is that the specific Falco source code builds successfully and that the tests pass.
|
||||
|
||||
As per [Falco Artifacts Scope (#1)](./20200506-artifacts-scope-part-1.md) proposal we provide three kind of Falco packages:
|
||||
|
||||
- DEB
|
||||
- RPM
|
||||
- Tarball
|
||||
|
||||
Thus, we have three repositories for the Falco stable releases:
|
||||
|
||||
- https://bintray.com/falcosecurity/deb
|
||||
- https://bintray.com/falcosecurity/rpm
|
||||
- https://bintray.com/falcosecurity/bin
|
||||
|
||||
And three repositories for the Falco development releases:
|
||||
|
||||
- https://bintray.com/falcosecurity/deb-dev
|
||||
- https://bintray.com/falcosecurity/rpm-dev
|
||||
- https://bintray.com/falcosecurity/bin-dev
|
||||
|
||||
## Drivers
|
||||
|
||||
The process of publishing a set of prebuilt Falco drivers is implemented by the **Drivers Build Grid (DBG)** in the [test-infra](https://github.com/falcosecurity/test-infra/tree/master/driverkit) repository (`driverkit` directory).
|
||||
|
||||
This process is driven by the configuration files (YAML) present in the `driverkit/config` directory in the [test-infra](https://github.com/falcosecurity/test-infra/tree/master/driverkit) repository.
|
||||
|
||||
Each of these files represents a prebuilt driver (eventually two: kernel module and eBPF probe, when possible) that will be published on [bintray](https://bintray.com/falcosecurity) if it builds correctly.
|
||||
|
||||
Every time the `driverkit/config` directory on the master branch has some changes from the previous commit the CI system, which you can find defined in the [.circleci/config.yml](https://github.com/falcosecurity/test-infra/blob/master/.circleci/config.yml) file, takes care of building and publishing all the drivers.
|
||||
|
||||
The driver versions we ship prebuilt drivers for are:
|
||||
|
||||
- the driver version associated with the last Falco stable version ([see here](https://github.com/falcosecurity/falco/blob/c4b7f17271d1a4ca533b2e672ecaaea5289ccdc5/cmake/modules/sysdig.cmake#L29))
|
||||
- the driver version associated with the penultimate Falco stable version
|
||||
|
||||
The prebuilt drivers get published into [this](https://bintray.com/falcosecurity/driver) generic artifacts repository.
|
||||
|
||||
You can also visualize the full list of prebuilt drivers by driver version visiting this [URL](https://dl.bintray.com/falcosecurity/driver).
|
||||
|
||||
### Notice
|
||||
|
||||
The generation of new prebuilt drivers takes usually place with a frequency of 1-2 weeks, on a **best-effort** basis.
|
||||
|
||||
Thus, it can happen the list of available prebuilt drivers does not yet contain the driver version currently on Falco master.
|
||||
|
||||
Nevertheless, this process is an open, auditable, and transparent one.
|
||||
|
||||
So, by sending a pull-request towards [test-infra](https://github.com/falcosecurity/test-infra) repository containing the configuration YAML files you can help the Falco community stay on track.
|
||||
|
||||
Some pull-requests you can look at to create your own are:
|
||||
|
||||
- https://github.com/falcosecurity/test-infra/pull/165
|
||||
- https://github.com/falcosecurity/test-infra/pull/163
|
||||
- https://github.com/falcosecurity/test-infra/pull/162
|
||||
|
||||
While, the documentation of the YAML configuration files can be found [here](https://github.com/falcosecurity/driverkit/blob/master/README.md).
|
||||
|
||||
## Container images
|
||||
|
||||
As per Falco packages, also the Falco official container images are **automatically** published to the [dockerhub](https://hub.docker.com/r/falcosecurity/falco).
|
||||
|
||||
These images are built and published in two cases:
|
||||
|
||||
- a pull request gets merged into the master branch (**Falco development releases**)
|
||||
- a new Falco release (git tag) happens (**Falco stable releases**)
|
||||
|
||||
For a detailed explanation of the container images we build and ship look at the following [documentation](https://github.com/falcosecurity/falco/blob/master/docker/README.md).
|
||||
@@ -1,102 +0,0 @@
|
||||
# Falco Artifacts Cleanup
|
||||
|
||||
This document reflects when and how we clean up the Falco artifacts from their storage location.
|
||||
|
||||
## Motivation
|
||||
|
||||
The [bintray](https://bintray.com/falcosecurity) open-source plan offers 10GB free space for storing artifacts.
|
||||
|
||||
They also kindly granted us an additional 5GB of free space.
|
||||
|
||||
## Goal
|
||||
|
||||
Keep the storage space usage under 15GB by cleaning up the [Falco artifacts](./20200506-artifacts-scope-part-1.md) from the [storage](./20200818-artifacts-storage).
|
||||
|
||||
## Status
|
||||
|
||||
To be implemented.
|
||||
|
||||
## Packages
|
||||
|
||||
### Tarballs from Falco master
|
||||
|
||||
At the moment of writing this document, this kind of Falco package requires approx. 50MB (maximum detected size) of storage space.
|
||||
|
||||
Since, historically, the [bin-dev](https://bintray.com/falcosecurity/bin-dev) repository is the less used one, this document proposes to keep only the last 10 **Falco development releases** it contains.
|
||||
|
||||
This means that the [bin-dev](https://bintray.com/falcosecurity/bin-dev) repository will take at maximum 500MB of storage space.
|
||||
|
||||
### DEB from Falco master
|
||||
|
||||
At the moment of writing this document, this kind of Falco package requires approx. 5.1MB (maximum detected size) of storage space.
|
||||
|
||||
Historically, every Falco release is composed by less than 50 merges (upper limit).
|
||||
|
||||
So, to theoretically retain all the **Falco development releases** that led to a Falco stable release, this document proposes to keep the last 50 Falco DEB packages.
|
||||
|
||||
This means that the [deb-dev](https://bintray.com/falcosecurity/deb-dev) repository will take at maximum 255MB of storage space.
|
||||
|
||||
### RPM from Falco master
|
||||
|
||||
At the moment of writing this document, this kind of Falco package requires approx. 4.3MB (maximum detected size) of storage space.
|
||||
|
||||
For the same exact reasons explained above this document proposes to keep the last 50 Falco RPM packages.
|
||||
|
||||
This means that the [rpm-dev](https://bintray.com/falcosecurity/rpm-dev) repository will take at maximum 215MB of storage space.
|
||||
|
||||
### Stable releases
|
||||
|
||||
This document proposes to retain all the stable releases.
|
||||
|
||||
This means that all the Falco packages present in the Falco stable release repositories will be kept.
|
||||
|
||||
The [bin](https://bintray.com/falcosecurity/bin) repository contains a Falco tarball package for every release.
|
||||
This means it grows in space of ~50MB each month.
|
||||
|
||||
The [deb](https://bintray.com/falcosecurity/deb) repository contains a Falco DEB package for every release.
|
||||
This means it grows in space of ~5MB each month.
|
||||
|
||||
The [rpm](https://bintray.com/falcosecurity/rpm) repository contains a Falco RPM package for every release.
|
||||
This means it grows in space of ~4.3MB each month.
|
||||
|
||||
### Considerations
|
||||
|
||||
Assuming the size of the packages does not surpass the numbers listed in the above sections, the **Falco development releases** will always take less that 1GB of artifacts storage space.
|
||||
|
||||
Assuming 12 stable releases at year, at the current size of packages, the **Falco stable releases** will take approx. 720MB of storage space every year.
|
||||
|
||||
### Implementation
|
||||
|
||||
The Falco CI will have a new CI job - called `cleanup/packages-dev` - responsible for removing the **Falco development releases** depending on the above plan.
|
||||
|
||||
This job will be triggered after the `publish/packages-dev` completed successfully.
|
||||
|
||||
## Drivers
|
||||
|
||||
As explained in the [Artifacts Storage](./20200818-artifacts-storage) proposal, we build the drivers for the **last two driver versions** associated with **latest Falco stable releases**.
|
||||
Then, we store those drivers into a [generic bintray repository](https://bintray.com/falcosecurity/driver) from which the installation process automatically downloads them, if suitable.
|
||||
|
||||
This document proposes to implement a cleanup mechanism that deletes all the other driver versions available.
|
||||
|
||||
At the moment of writing, considering only the last two driver versions (**ae104eb**, **85c8895**) associated with the latest Falco stable releases, we ship ~340 eBPF drivers, each accounting for ~3.1MB of storage space, and 1512 kernel modules (~3.1MB size each, too).
|
||||
|
||||
Thus, we obtain an estimate of approx. 2.875GB for **each** driver version.
|
||||
|
||||
This document proposes to only store the last two driver versions associates with the latest Falco stable releases. And deleting the other ones.
|
||||
|
||||
This way, assuming the number of prebuilt drivers does not skyrocket, we can reasonably estimate the storage space used by prebuilt drivers to be around 6GB.
|
||||
|
||||
Notice that, in case a Falco stable release will not depend on a new driver version, this means the last two driver versions will, in this case, cover more than the two Falco stable releases.
|
||||
|
||||
### Archivation
|
||||
|
||||
Since the process of building drivers is time and resource consuming, this document also proposes to move the driver versions in other storage facilities.
|
||||
|
||||
The candidate is an AWS S3 bucket responsible for holding the deleted driver version files.
|
||||
|
||||
### Implementation
|
||||
|
||||
The [test-infra](https://github.com/falcosecurity/test-infra) CI, specifically its part dedicated to run the **Drivers Build Grid** that runs every time it detects changes into the `driverkit` directory of the [test-infra](https://github.com/falcosecurity/test-infra) repository,
|
||||
will have a new job - called `drivers/cleanup` - responsible for removing all the Falco driver versions except the last two.
|
||||
|
||||
This job will be triggered after the `drivers/publish` completed successfully on the master branch.
|
||||
@@ -1,137 +0,0 @@
|
||||
# Falco Drivers Storage S3
|
||||
|
||||
Supersedes: [20200818-artifacts-storage.md#drivers](20200818-artifacts-storage.md#drivers)
|
||||
|
||||
Supersedes: [20200901-artifacts-cleanup.md#drivers](20200901-artifacts-cleanup.md#drivers)
|
||||
|
||||
## Introduction
|
||||
|
||||
In the past days, as many people probably noticed, Bintray started rate-limiting our users, effectively preventing them from downloading any kernel module, rpm/deb package or any pre-built dependency we host there.
|
||||
|
||||
This does not only interrupt the workflow of our users but also the workflow of the contributors, since without bintray most of our container images and CMake files can’t download the dependencies we mirror.
|
||||
|
||||
### What is the cause?
|
||||
|
||||
We had a spike in adoption apparently, either a user with many nodes or an increased number of users. We don’t know this detail specifically yet because bintray does not give us very fine-grained statistics on this.
|
||||
|
||||
This is the 30-days history:
|
||||
|
||||

|
||||
|
||||
As you can see, we can only see that they downloaded the latest kernel module driver version, however we can’t see if:
|
||||
|
||||
* It’s a single source or many different users
|
||||
|
||||
* What is the kernel/OS they are using
|
||||
|
||||
### What do we host on Bintray?
|
||||
|
||||
* RPM packages: high traffic but very manageable ~90k downloads a month
|
||||
|
||||
* Deb packages:low traffic ~5k downloads a month
|
||||
|
||||
* Pre-built image Dependencies: low traffic, will eventually disappear in the future
|
||||
|
||||
* Kernel modules: very high traffic, 700k downloads in 10 days, this is what is causing the current problems. They are primarily used by users of our container images.
|
||||
|
||||
* eBPF probes: low traffic ~5k downloads a month
|
||||
|
||||
### Motivations to go to S3 instead of Bintray for the Drivers
|
||||
|
||||
Bintray does an excellent service at building the rpm/deb structures for us, however we also use them for S3-like storage for the drivers. We have ten thousand files hosted there and the combinations are infinite.
|
||||
|
||||
|
||||
Before today, we had many issues with storage even without the spike in users we are seeing since the last ten days.
|
||||
|
||||
## Context on AWS
|
||||
|
||||
Amazon AWS, recently gave credits to the Falco project to operate some parts of the infrastructure on AWS. The CNCF is providing a sub-account we are already using for the migration of the other pieces (like Prow).
|
||||
|
||||
## Interactions with other teams and the CNCF
|
||||
|
||||
* The setup on the AWS account side already done, this is all technical work.
|
||||
|
||||
* We need to open a CNCF service account ticket for the download.falco.org subdomain to point to the S3 bucket we want to use
|
||||
|
||||
## The Plan
|
||||
|
||||
We want to propose to move the drivers and the container dependencies to S3.
|
||||
|
||||
#### Moving means:
|
||||
|
||||
* We create a public S3 bucket with [stats enabled](https://docs.aws.amazon.com/AmazonS3/latest/dev/analytics-storage-class.html)
|
||||
|
||||
* We attach the bucket to a cloudfront distribution behind the download.falco.org subdomain
|
||||
|
||||
* We move the current content keeping the same web server directory structure
|
||||
|
||||
* We change the Falco Dockerfiles and driver loader script accordingly
|
||||
|
||||
* We update test-infra to push the drivers to S3
|
||||
|
||||
* Once we have the drivers in S3, we can ask bintray to relax the limits for this month so that our users are able to download the other packages we keep there. Otherwise they will have to wait until November 1st. We only want to do that after the moving because otherwise we will hit the limits pretty quickly.
|
||||
|
||||
#### The repositories we want to move are:
|
||||
|
||||
* [https://bintray.com/falcosecurity/driver](https://bintray.com/falcosecurity/driver) will become https://download.falco.org/driver
|
||||
|
||||
* [https://bintray.com/falcosecurity/dependencies](https://bintray.com/falcosecurity/dependencies) will become https://download.falco.org/dependencies
|
||||
|
||||
#### Changes in Falco
|
||||
|
||||
* [Search for bintray ](https://github.com/falcosecurity/falco/search?p=2&q=bintray)on the Falco repo and replace the URL for the CMake and Docker files.
|
||||
|
||||
* It’s very important to change the DRIVERS_REPO environment variable [here](https://github.com/falcosecurity/falco/blob/0a33f555eb8e019806b46fea8b80a6302a935421/CMakeLists.txt#L86) - this is what updates the falco-driver-loader scripts that the users and container images use to fetch the module
|
||||
|
||||
#### Changes in Test Infra
|
||||
|
||||
* We need to use the S3 cli instead of jfrog cli to upload to the s3 bucket after building [here](https://github.com/falcosecurity/test-infra/blob/master/.circleci/config.yml)
|
||||
|
||||
* We can probably remove jfrog from that repo since it only deals with drivers and drivers are being put on S3 now
|
||||
|
||||
* Instructions on how to setup the S3 directory structure [here](https://falco.org/docs/installation/#install-driver)
|
||||
|
||||
* `/$driver_version$/falco_$target$_$kernelrelease$_$kernelversion$.[ko|o]`
|
||||
|
||||
#### Changes to Falco website
|
||||
|
||||
* Changes should not be necessary, we are not updating the way people install Falco but only the driver. The driver is managed by a script we can change.
|
||||
|
||||
## Mitigation and next steps for the users
|
||||
|
||||
* **The average users should be good to go now, Bintray raised our limits and we have some room to do this without requiring manual steps on your end**
|
||||
|
||||
* **Users that can’t wait for us to have the S3 setup done: **can setup an S3 as driver repo themselves, push the drivers they need to it after compiling them (they can use [Driverkit](https://github.com/falcosecurity/driverkit) for that) Instructions on how to setup the S3 directory structure [here](https://falco.org/docs/installation/#install-driver).
|
||||
|
||||
* **Users that can’t wait but don’t want to setup a webserver themselves**: the falco-driver-loader script can also compile the module for you. Make sure to install the kernel-headers on your nodes.
|
||||
|
||||
* **Users that can wait** we will approve this document and act on the plan described here by providing the DRIVERS_REPO at [https://download.falco.org/driver](https://download.falco.org/driver) that then you can use
|
||||
|
||||
### How to use an alternative DRIVERS_REPO ?
|
||||
|
||||
**On bash:**
|
||||
|
||||
export DRIVERS_REPO=https://your-url-here
|
||||
|
||||
**Docker**
|
||||
|
||||
Pass it as environment variable using the docker run flag -e - for example:
|
||||
|
||||
docker run -e DRIVERS_REPO=[https://your-url-here](https://your-url-here)
|
||||
|
||||
**Kubernetes**
|
||||
|
||||
spec:
|
||||
|
||||
containers:
|
||||
|
||||
- env:
|
||||
|
||||
- name: DRIVERS_REPO
|
||||
|
||||
value: https://your-url-here
|
||||
|
||||
## Release
|
||||
|
||||
Next release is on December 1st, we want to rollout a hotfix 0.26.2 release that only contains the updated script before that date so that users don’t get confused and we can just tell them "update Falco" to get the thing working again.
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 43 KiB |
@@ -37,7 +37,8 @@ if(DEFINED FALCO_COMPONENT)
|
||||
COMPONENT "${FALCO_COMPONENT}"
|
||||
DESTINATION "${FALCO_ETC_DIR}"
|
||||
RENAME "${FALCO_LOCAL_RULES_DEST_FILENAME}")
|
||||
# Intentionally *not* installing application_rules.yaml. Not needed when falco is embedded in other projects.
|
||||
|
||||
# Intentionally *not* installing application_rules.yaml. Not needed when falco is embedded in other projects.
|
||||
else()
|
||||
install(
|
||||
FILES falco_rules.yaml
|
||||
@@ -56,8 +57,8 @@ else()
|
||||
|
||||
install(
|
||||
FILES application_rules.yaml
|
||||
DESTINATION "${FALCO_ETC_DIR}/rules.available"
|
||||
DESTINATION "/etc/falco/rules.available"
|
||||
RENAME "${FALCO_APP_RULES_DEST_FILENAME}")
|
||||
|
||||
install(DIRECTORY DESTINATION "${FALCO_ETC_DIR}/rules.d")
|
||||
install(DIRECTORY DESTINATION "/etc/falco/rules.d")
|
||||
endif()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -44,13 +44,18 @@
|
||||
items: ["vpa-recommender", "vpa-updater"]
|
||||
|
||||
- list: allowed_k8s_users
|
||||
items: [
|
||||
"minikube", "minikube-user", "kubelet", "kops", "admin", "kube", "kube-proxy", "kube-apiserver-healthcheck",
|
||||
"kubernetes-admin",
|
||||
vertical_pod_autoscaler_users,
|
||||
cluster-autoscaler,
|
||||
"system:addon-manager",
|
||||
"cloud-controller-manager"
|
||||
items:
|
||||
[
|
||||
"minikube",
|
||||
"minikube-user",
|
||||
"kubelet",
|
||||
"kops",
|
||||
"admin",
|
||||
"kube",
|
||||
"kube-proxy",
|
||||
"kube-apiserver-healthcheck",
|
||||
"kubernetes-admin",
|
||||
vertical_pod_autoscaler_users,
|
||||
]
|
||||
|
||||
- rule: Disallowed K8s User
|
||||
@@ -118,6 +123,7 @@
|
||||
- macro: health_endpoint
|
||||
condition: ka.uri=/healthz
|
||||
|
||||
# requires FALCO_ENGINE_VERSION 5
|
||||
- rule: Create Disallowed Pod
|
||||
desc: >
|
||||
Detect an attempt to start a pod with a container image outside of a list of allowed images.
|
||||
@@ -127,6 +133,7 @@
|
||||
source: k8s_audit
|
||||
tags: [k8s]
|
||||
|
||||
# requires FALCO_ENGINE_VERSION 5
|
||||
- rule: Create Privileged Pod
|
||||
desc: >
|
||||
Detect an attempt to start a pod with a privileged container
|
||||
@@ -139,7 +146,8 @@
|
||||
- macro: sensitive_vol_mount
|
||||
condition: >
|
||||
(ka.req.pod.volumes.hostpath intersects (/proc, /var/run/docker.sock, /, /etc, /root, /var/run/crio/crio.sock, /home/admin, /var/lib/kubelet, /var/lib/kubelet/pki, /etc/kubernetes, /etc/kubernetes/manifests))
|
||||
|
||||
|
||||
# requires FALCO_ENGINE_VERSION 5
|
||||
- rule: Create Sensitive Mount Pod
|
||||
desc: >
|
||||
Detect an attempt to start a pod with a volume from a sensitive host directory (i.e. /proc).
|
||||
@@ -151,6 +159,7 @@
|
||||
tags: [k8s]
|
||||
|
||||
# Corresponds to K8s CIS Benchmark 1.7.4
|
||||
# requires FALCO_ENGINE_VERSION 5
|
||||
- rule: Create HostNetwork Pod
|
||||
desc: Detect an attempt to start a pod using the host network.
|
||||
condition: kevt and pod and kcreate and ka.req.pod.host_network intersects (true) and not ka.req.pod.containers.image.repository in (falco_hostnetwork_images)
|
||||
@@ -182,7 +191,7 @@
|
||||
|
||||
- rule: Create/Modify Configmap With Private Credentials
|
||||
desc: >
|
||||
Detect creating/modifying a configmap containing a private credential (aws key, password, etc.)
|
||||
Detect creating/modifying a configmap containing a private credential (aws key, password, etc.)
|
||||
condition: kevt and configmap and kmodify and contains_private_credentials
|
||||
output: K8s configmap with private credential (user=%ka.user.name verb=%ka.verb configmap=%ka.req.configmap.name config=%ka.req.configmap.obj)
|
||||
priority: WARNING
|
||||
@@ -220,19 +229,6 @@
|
||||
source: k8s_audit
|
||||
tags: [k8s]
|
||||
|
||||
- macro: user_known_pod_debug_activities
|
||||
condition: (k8s_audit_never_true)
|
||||
|
||||
# Only works when feature gate EphemeralContainers is enabled
|
||||
- rule: EphemeralContainers Created
|
||||
desc: >
|
||||
Detect any ephemeral container created
|
||||
condition: kevt and pod_subresource and kmodify and ka.target.subresource in (ephemeralcontainers) and not user_known_pod_debug_activities
|
||||
output: Ephemeral container is created in pod (user=%ka.user.name pod=%ka.target.name ns=%ka.target.namespace ephemeral_container_name=%jevt.value[/requestObject/ephemeralContainers/0/name] ephemeral_container_image=%jevt.value[/requestObject/ephemeralContainers/0/image])
|
||||
priority: NOTICE
|
||||
source: k8s_audit
|
||||
tags: [k8s]
|
||||
|
||||
# In a local/user rules fie, you can append to this list to add additional allowed namespaces
|
||||
- list: allowed_namespaces
|
||||
items: [kube-system, kube-public, default]
|
||||
@@ -245,48 +241,17 @@
|
||||
source: k8s_audit
|
||||
tags: [k8s]
|
||||
|
||||
# Only defined for backwards compatibility. Use the more specific
|
||||
# user_allowed_kube_namespace_image_list instead.
|
||||
- list: user_trusted_image_list
|
||||
items: []
|
||||
|
||||
- list: user_allowed_kube_namespace_image_list
|
||||
items: [user_trusted_image_list]
|
||||
|
||||
# Only defined for backwards compatibility. Use the more specific
|
||||
# allowed_kube_namespace_image_list instead.
|
||||
- list: k8s_image_list
|
||||
items: []
|
||||
|
||||
- list: allowed_kube_namespace_image_list
|
||||
items: [
|
||||
gcr.io/google-containers/prometheus-to-sd,
|
||||
gcr.io/projectcalico-org/node,
|
||||
gke.gcr.io/addon-resizer,
|
||||
gke.gcr.io/heapster,
|
||||
gke.gcr.io/gke-metadata-server,
|
||||
k8s.gcr.io/ip-masq-agent-amd64,
|
||||
k8s.gcr.io/kube-apiserver,
|
||||
gke.gcr.io/kube-proxy,
|
||||
gke.gcr.io/netd-amd64,
|
||||
k8s.gcr.io/addon-resizer
|
||||
k8s.gcr.io/prometheus-to-sd,
|
||||
k8s.gcr.io/k8s-dns-dnsmasq-nanny-amd64,
|
||||
k8s.gcr.io/k8s-dns-kube-dns-amd64,
|
||||
k8s.gcr.io/k8s-dns-sidecar-amd64,
|
||||
k8s.gcr.io/metrics-server-amd64,
|
||||
kope/kube-apiserver-healthcheck,
|
||||
k8s_image_list
|
||||
]
|
||||
|
||||
- macro: allowed_kube_namespace_pods
|
||||
condition: (ka.req.pod.containers.image.repository in (user_allowed_kube_namespace_image_list) or
|
||||
ka.req.pod.containers.image.repository in (allowed_kube_namespace_image_list))
|
||||
- macro: trusted_pod
|
||||
condition: (ka.req.pod.containers.image.repository in (user_trusted_image_list))
|
||||
|
||||
# Detect any new pod created in the kube-system namespace
|
||||
# requires FALCO_ENGINE_VERSION 5
|
||||
- rule: Pod Created in Kube Namespace
|
||||
desc: Detect any attempt to create a pod in the kube-system or kube-public namespaces
|
||||
condition: kevt and pod and kcreate and ka.target.namespace in (kube-system, kube-public) and not allowed_kube_namespace_pods
|
||||
condition: kevt and pod and kcreate and ka.target.namespace in (kube-system, kube-public) and not trusted_pod
|
||||
output: Pod created in kube namespace (user=%ka.user.name pod=%ka.resp.name ns=%ka.target.namespace images=%ka.req.pod.containers.image)
|
||||
priority: WARNING
|
||||
source: k8s_audit
|
||||
@@ -312,8 +277,7 @@
|
||||
# normal operation.
|
||||
- rule: System ClusterRole Modified/Deleted
|
||||
desc: Detect any attempt to modify/delete a ClusterRole/Role starting with system
|
||||
condition: kevt and (role or clusterrole) and (kmodify or kdelete) and (ka.target.name startswith "system:") and
|
||||
not ka.target.name in (system:coredns, system:managed-certificate-controller)
|
||||
condition: kevt and (role or clusterrole) and (kmodify or kdelete) and (ka.target.name startswith "system:") and ka.target.name!="system:coredns"
|
||||
output: System ClusterRole/Role modified or deleted (user=%ka.user.name role=%ka.target.name ns=%ka.target.namespace action=%ka.verb)
|
||||
priority: WARNING
|
||||
source: k8s_audit
|
||||
@@ -329,6 +293,7 @@
|
||||
source: k8s_audit
|
||||
tags: [k8s]
|
||||
|
||||
# requires FALCO_ENGINE_VERSION 5
|
||||
- rule: ClusterRole With Wildcard Created
|
||||
desc: Detect any attempt to create a Role/ClusterRole with wildcard resources or verbs
|
||||
condition: kevt and (role or clusterrole) and kcreate and (ka.req.role.rules.resources intersects ("*") or ka.req.role.rules.verbs intersects ("*"))
|
||||
@@ -341,6 +306,7 @@
|
||||
condition: >
|
||||
(ka.req.role.rules.verbs intersects (create, update, patch, delete, deletecollection))
|
||||
|
||||
# requires FALCO_ENGINE_VERSION 5
|
||||
- rule: ClusterRole With Write Privileges Created
|
||||
desc: Detect any attempt to create a Role/ClusterRole that can perform write-related actions
|
||||
condition: kevt and (role or clusterrole) and kcreate and writable_verbs
|
||||
@@ -349,6 +315,7 @@
|
||||
source: k8s_audit
|
||||
tags: [k8s]
|
||||
|
||||
# requires FALCO_ENGINE_VERSION 5
|
||||
- rule: ClusterRole With Pod Exec Created
|
||||
desc: Detect any attempt to create a Role/ClusterRole that can exec to pods
|
||||
condition: kevt and (role or clusterrole) and kcreate and ka.req.role.rules.resources intersects ("pods/exec")
|
||||
@@ -512,20 +479,26 @@
|
||||
source: k8s_audit
|
||||
tags: [k8s]
|
||||
|
||||
|
||||
# This macro disables following rule, change to k8s_audit_never_true to enable it
|
||||
- macro: allowed_full_admin_users
|
||||
condition: (k8s_audit_always_true)
|
||||
|
||||
# This list includes some of the default user names for an administrator in several K8s installations
|
||||
- list: full_admin_k8s_users
|
||||
items: ["admin", "kubernetes-admin", "kubernetes-admin@kubernetes", "kubernetes-admin@cluster.local", "minikube-user"]
|
||||
items:
|
||||
[
|
||||
"admin",
|
||||
"kubernetes-admin",
|
||||
"kubernetes-admin@kubernetes",
|
||||
"kubernetes-admin@cluster.local",
|
||||
"minikube-user",
|
||||
]
|
||||
|
||||
# This rules detect an operation triggered by an user name that is
|
||||
# included in the list of those that are default administrators upon
|
||||
# cluster creation. This may signify a permission setting too broader.
|
||||
# As we can't check for role of the user on a general ka.* event, this
|
||||
# may or may not be an administrator. Customize the full_admin_k8s_users
|
||||
# This rules detect an operation triggered by an user name that is
|
||||
# included in the list of those that are default administrators upon
|
||||
# cluster creation. This may signify a permission setting too broader.
|
||||
# As we can't check for role of the user on a general ka.* event, this
|
||||
# may or may not be an administrator. Customize the full_admin_k8s_users
|
||||
# list to your needs, and activate at your discrection.
|
||||
|
||||
# # How to test:
|
||||
@@ -537,7 +510,7 @@
|
||||
condition: >
|
||||
kevt
|
||||
and non_system_user
|
||||
and ka.user.name in (full_admin_k8s_users)
|
||||
and ka.user.name in (admin_k8s_users)
|
||||
and not allowed_full_admin_users
|
||||
output: K8s Operation performed by full admin user (user=%ka.user.name target=%ka.target.name/%ka.target.resource verb=%ka.verb uri=%ka.uri resp=%ka.response.code)
|
||||
priority: WARNING
|
||||
@@ -575,7 +548,7 @@
|
||||
output: >
|
||||
K8s Ingress Without TLS Cert Created (user=%ka.user.name ingress=%ka.target.name
|
||||
namespace=%ka.target.namespace)
|
||||
source: k8s_audit
|
||||
source: k8s_audit
|
||||
priority: WARNING
|
||||
tags: [k8s, network]
|
||||
|
||||
@@ -621,4 +594,3 @@
|
||||
priority: WARNING
|
||||
source: k8s_audit
|
||||
tags: [k8s]
|
||||
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
usage() {
|
||||
echo "usage: $0 -p 0987654321 -r <deb-dev|rpm-dev|bin-dev>"
|
||||
exit 1
|
||||
}
|
||||
|
||||
user=poiana
|
||||
|
||||
# Get the versions to delete.
|
||||
#
|
||||
# $1: repository to lookup
|
||||
# $2: number of versions to skip.
|
||||
get_versions() {
|
||||
# The API endpoint returns the Falco package versions sort by most recent.
|
||||
IFS=$'\n' read -r -d '' -a all < <(curl -s --header "Content-Type: application/json" "https://api.bintray.com/packages/falcosecurity/$1/falco" | jq -r '.versions | .[]' | tail -n "+$2")
|
||||
}
|
||||
|
||||
# Remove all the versions (${all[@]} array).
|
||||
#
|
||||
# $1: repository containing the versions.
|
||||
rem_versions() {
|
||||
for i in "${!all[@]}";
|
||||
do
|
||||
JFROG_CLI_LOG_LEVEL=DEBUG jfrog bt vd --quiet --user "${user}" --key "${pass}" "falcosecurity/$1/falco/${all[$i]}"
|
||||
done
|
||||
}
|
||||
|
||||
while getopts ":p::r:" opt; do
|
||||
case "${opt}" in
|
||||
p )
|
||||
pass=${OPTARG}
|
||||
;;
|
||||
r )
|
||||
repo="${OPTARG}"
|
||||
[[ "${repo}" == "deb-dev" || "${repo}" == "rpm-dev" || "${repo}" == "bin-dev" ]] || usage
|
||||
;;
|
||||
: )
|
||||
echo "invalid option: ${OPTARG} requires an argument" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
\?)
|
||||
echo "invalid option: ${OPTARG}" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND-1))
|
||||
|
||||
if [ -z "${pass}" ] || [ -z "${repo}" ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
skip=51
|
||||
if [[ "${repo}" == "bin-dev" ]]; then
|
||||
skip=11
|
||||
fi
|
||||
|
||||
get_versions "${repo}" ${skip}
|
||||
echo "number of versions to delete: ${#all[@]}"
|
||||
rem_versions "${repo}"
|
||||
@@ -143,41 +143,33 @@ load_kernel_module_compile() {
|
||||
# skip dkms on UEK hosts because it will always fail
|
||||
if [[ $(uname -r) == *uek* ]]; then
|
||||
echo "* Skipping dkms install for UEK host"
|
||||
return
|
||||
fi
|
||||
|
||||
if ! hash dkms &>/dev/null; then
|
||||
echo "* Skipping dkms install (dkms not found)"
|
||||
return
|
||||
fi
|
||||
|
||||
# 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 -r); do
|
||||
echo "* Trying to dkms install ${DRIVER_NAME} module with GCC ${CURRENT_GCC}"
|
||||
echo "#!/usr/bin/env bash" > /tmp/falco-dkms-make
|
||||
echo "make CC=${CURRENT_GCC} \$@" >> /tmp/falco-dkms-make
|
||||
chmod +x /tmp/falco-dkms-make
|
||||
if dkms install --directive="MAKE='/tmp/falco-dkms-make'" -m "${DRIVER_NAME}" -v "${DRIVER_VERSION}" -k "${KERNEL_RELEASE}" 2>/dev/null; then
|
||||
echo "* ${DRIVER_NAME} module installed in dkms, trying to insmod"
|
||||
if insmod "/var/lib/dkms/${DRIVER_NAME}/${DRIVER_VERSION}/${KERNEL_RELEASE}/${ARCH}/module/${DRIVER_NAME}.ko" > /dev/null 2>&1; then
|
||||
echo "* Success: ${DRIVER_NAME} module found and loaded in dkms"
|
||||
exit 0
|
||||
elif insmod "/var/lib/dkms/${DRIVER_NAME}/${DRIVER_VERSION}/${KERNEL_RELEASE}/${ARCH}/module/${DRIVER_NAME}.ko.xz" > /dev/null 2>&1; then
|
||||
echo "* Success: ${DRIVER_NAME} module found and loaded in dkms (xz)"
|
||||
exit 0
|
||||
else
|
||||
if hash dkms &>/dev/null; then
|
||||
echo "* Trying to dkms install ${DRIVER_NAME} module"
|
||||
if dkms install -m "${DRIVER_NAME}" -v "${DRIVER_VERSION}" -k "${KERNEL_RELEASE}" 2>/dev/null; then
|
||||
echo "* ${DRIVER_NAME} module installed in dkms, trying to insmod"
|
||||
if insmod "/var/lib/dkms/${DRIVER_NAME}/${DRIVER_VERSION}/${KERNEL_RELEASE}/${ARCH}/module/${DRIVER_NAME}.ko" > /dev/null 2>&1; then
|
||||
echo "* Success: ${DRIVER_NAME} module found and loaded in dkms"
|
||||
exit 0
|
||||
elif insmod "/var/lib/dkms/${DRIVER_NAME}/${DRIVER_VERSION}/${KERNEL_RELEASE}/${ARCH}/module/${DRIVER_NAME}.ko.xz" > /dev/null 2>&1; then
|
||||
echo "* Success: ${DRIVER_NAME} module found and loaded in dkms (xz)"
|
||||
exit 0
|
||||
else
|
||||
echo "* Unable to insmod ${DRIVER_NAME} module"
|
||||
fi
|
||||
else
|
||||
echo "* Unable to insmod ${DRIVER_NAME} module"
|
||||
DKMS_LOG="/var/lib/dkms/${DRIVER_NAME}/${DRIVER_VERSION}/build/make.log"
|
||||
if [ -f "${DKMS_LOG}" ]; then
|
||||
echo "* Running dkms build failed, dumping ${DKMS_LOG}"
|
||||
cat "${DKMS_LOG}"
|
||||
else
|
||||
echo "* Running dkms build failed, couldn't find ${DKMS_LOG}"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
DKMS_LOG="/var/lib/dkms/${DRIVER_NAME}/${DRIVER_VERSION}/build/make.log"
|
||||
if [ -f "${DKMS_LOG}" ]; then
|
||||
echo "* Running dkms build failed, dumping ${DKMS_LOG} (with GCC ${CURRENT_GCC})"
|
||||
cat "${DKMS_LOG}"
|
||||
else
|
||||
echo "* Running dkms build failed, couldn't find ${DKMS_LOG} (with GCC ${CURRENT_GCC})"
|
||||
fi
|
||||
echo "* Skipping dkms install (dkms not found)"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
load_kernel_module_download() {
|
||||
@@ -220,7 +212,7 @@ load_kernel_module() {
|
||||
rmmod "${DRIVER_NAME}" 2>/dev/null
|
||||
WAIT_TIME=0
|
||||
KMOD_NAME=$(echo "${DRIVER_NAME}" | tr "-" "_")
|
||||
while lsmod | cut -d' ' -f1 | grep -qx "${KMOD_NAME}" && [ $WAIT_TIME -lt "${MAX_RMMOD_WAIT}" ]; do
|
||||
while lsmod | grep "${KMOD_NAME}" > /dev/null 2>&1 && [ $WAIT_TIME -lt "${MAX_RMMOD_WAIT}" ]; do
|
||||
if rmmod "${DRIVER_NAME}" 2>/dev/null; then
|
||||
echo "* Unloading ${DRIVER_NAME} module succeeded after ${WAIT_TIME}s"
|
||||
break
|
||||
@@ -232,7 +224,7 @@ load_kernel_module() {
|
||||
sleep 1
|
||||
done
|
||||
|
||||
if lsmod | cut -d' ' -f1 | grep -qx "${KMOD_NAME}" > /dev/null 2>&1; then
|
||||
if lsmod | grep "${KMOD_NAME}" > /dev/null 2>&1; then
|
||||
echo "* ${DRIVER_NAME} module seems to still be loaded, hoping the best"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
@@ -41,4 +41,4 @@ stdout_output:
|
||||
|
||||
program_output:
|
||||
enabled: true
|
||||
program: cat >> /tmp/falco_outputs/program_output.txt
|
||||
program: cat > /tmp/falco_outputs/program_output.txt
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
# File containing Falco rules, loaded at startup.
|
||||
rules_file: /etc/falco_rules.yaml
|
||||
|
||||
# Whether to output events in json or text
|
||||
json_output: false
|
||||
|
||||
# Send information logs to stderr and/or syslog Note these are *not* security
|
||||
# notification logs! These are just Falco lifecycle (and possibly error) logs.
|
||||
log_stderr: false
|
||||
log_syslog: false
|
||||
|
||||
# Where security notifications should go.
|
||||
# Multiple outputs can be enabled.
|
||||
|
||||
syslog_output:
|
||||
enabled: false
|
||||
|
||||
file_output:
|
||||
enabled: false
|
||||
|
||||
stdout_output:
|
||||
enabled: true
|
||||
|
||||
program_output:
|
||||
enabled: false
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright (C) 2019 The Falco Authors.
|
||||
#
|
||||
@@ -31,7 +31,6 @@ from avocado.utils import process
|
||||
from watchdog.observers import Observer
|
||||
from watchdog.events import PatternMatchingEventHandler
|
||||
|
||||
|
||||
class FalcoTest(Test):
|
||||
|
||||
def setUp(self):
|
||||
@@ -50,20 +49,17 @@ class FalcoTest(Test):
|
||||
self.stdout_is = self.params.get('stdout_is', '*', default='')
|
||||
self.stderr_is = self.params.get('stderr_is', '*', default='')
|
||||
|
||||
self.stdout_contains = self.params.get(
|
||||
'stdout_contains', '*', default='')
|
||||
self.stdout_contains = self.params.get('stdout_contains', '*', default='')
|
||||
|
||||
if not isinstance(self.stdout_contains, list):
|
||||
self.stdout_contains = [self.stdout_contains]
|
||||
|
||||
self.stderr_contains = self.params.get(
|
||||
'stderr_contains', '*', default='')
|
||||
self.stderr_contains = self.params.get('stderr_contains', '*', default='')
|
||||
|
||||
if not isinstance(self.stderr_contains, list):
|
||||
self.stderr_contains = [self.stderr_contains]
|
||||
|
||||
self.stdout_not_contains = self.params.get(
|
||||
'stdout_not_contains', '*', default='')
|
||||
self.stdout_not_contains = self.params.get('stdout_not_contains', '*', default='')
|
||||
|
||||
if not isinstance(self.stdout_not_contains, list):
|
||||
if self.stdout_not_contains == '':
|
||||
@@ -71,8 +67,7 @@ class FalcoTest(Test):
|
||||
else:
|
||||
self.stdout_not_contains = [self.stdout_not_contains]
|
||||
|
||||
self.stderr_not_contains = self.params.get(
|
||||
'stderr_not_contains', '*', default='')
|
||||
self.stderr_not_contains = self.params.get('stderr_not_contains', '*', default='')
|
||||
|
||||
if not isinstance(self.stderr_not_contains, list):
|
||||
if self.stderr_not_contains == '':
|
||||
@@ -88,18 +83,15 @@ class FalcoTest(Test):
|
||||
self.trace_file = os.path.join(build_dir, "test", self.trace_file)
|
||||
|
||||
self.json_output = self.params.get('json_output', '*', default=False)
|
||||
self.json_include_output_property = self.params.get(
|
||||
'json_include_output_property', '*', default=True)
|
||||
self.json_include_output_property = self.params.get('json_include_output_property', '*', default=True)
|
||||
self.all_events = self.params.get('all_events', '*', default=False)
|
||||
self.priority = self.params.get('priority', '*', default='debug')
|
||||
self.rules_file = self.params.get(
|
||||
'rules_file', '*', default=os.path.join(self.basedir, '../rules/falco_rules.yaml'))
|
||||
self.rules_file = self.params.get('rules_file', '*', default=os.path.join(self.basedir, '../rules/falco_rules.yaml'))
|
||||
|
||||
if not isinstance(self.rules_file, list):
|
||||
self.rules_file = [self.rules_file]
|
||||
|
||||
self.validate_rules_file = self.params.get(
|
||||
'validate_rules_file', '*', default=False)
|
||||
self.validate_rules_file = self.params.get('validate_rules_file', '*', default=False)
|
||||
|
||||
if self.validate_rules_file == False:
|
||||
self.validate_rules_file = []
|
||||
@@ -126,15 +118,13 @@ class FalcoTest(Test):
|
||||
file = os.path.join(self.basedir, file)
|
||||
self.rules_args = self.rules_args + "-r " + file + " "
|
||||
|
||||
self.conf_file = self.params.get(
|
||||
'conf_file', '*', default=os.path.join(self.basedir, '../falco.yaml'))
|
||||
self.conf_file = self.params.get('conf_file', '*', default=os.path.join(self.basedir, '../falco.yaml'))
|
||||
if not os.path.isabs(self.conf_file):
|
||||
self.conf_file = os.path.join(self.basedir, self.conf_file)
|
||||
|
||||
self.run_duration = self.params.get('run_duration', '*', default='')
|
||||
|
||||
self.disabled_rules = self.params.get(
|
||||
'disabled_rules', '*', default='')
|
||||
self.disabled_rules = self.params.get('disabled_rules', '*', default='')
|
||||
|
||||
if self.disabled_rules == '':
|
||||
self.disabled_rules = []
|
||||
@@ -147,8 +137,7 @@ class FalcoTest(Test):
|
||||
for rule in self.disabled_rules:
|
||||
self.disabled_args = self.disabled_args + "-D " + rule + " "
|
||||
|
||||
self.detect_counts = self.params.get(
|
||||
'detect_counts', '*', default=False)
|
||||
self.detect_counts = self.params.get('detect_counts', '*', default=False)
|
||||
if self.detect_counts == False:
|
||||
self.detect_counts = {}
|
||||
else:
|
||||
@@ -158,8 +147,7 @@ class FalcoTest(Test):
|
||||
detect_counts[key] = value
|
||||
self.detect_counts = detect_counts
|
||||
|
||||
self.rules_warning = self.params.get(
|
||||
'rules_warning', '*', default=False)
|
||||
self.rules_warning = self.params.get('rules_warning', '*', default=False)
|
||||
if self.rules_warning == False:
|
||||
self.rules_warning = set()
|
||||
else:
|
||||
@@ -184,11 +172,9 @@ class FalcoTest(Test):
|
||||
|
||||
self.package = self.params.get('package', '*', default='None')
|
||||
|
||||
self.addl_docker_run_args = self.params.get(
|
||||
'addl_docker_run_args', '*', default='')
|
||||
self.addl_docker_run_args = self.params.get('addl_docker_run_args', '*', default='')
|
||||
|
||||
self.copy_local_driver = self.params.get(
|
||||
'copy_local_driver', '*', default=False)
|
||||
self.copy_local_driver = self.params.get('copy_local_driver', '*', default=False)
|
||||
|
||||
# Used by possibly_copy_local_driver as well as docker run
|
||||
self.module_dir = os.path.expanduser("~/.falco")
|
||||
@@ -211,33 +197,9 @@ class FalcoTest(Test):
|
||||
os.makedirs(filedir)
|
||||
self.outputs = outputs
|
||||
|
||||
self.output_strictly_contains = self.params.get(
|
||||
'output_strictly_contains', '*', default='')
|
||||
|
||||
if self.output_strictly_contains == '':
|
||||
self.output_strictly_contains = {}
|
||||
else:
|
||||
output_strictly_contains = []
|
||||
for item in self.output_strictly_contains:
|
||||
for key, value in list(item.items()):
|
||||
output = {}
|
||||
output['actual'] = key
|
||||
output['expected'] = value
|
||||
output_strictly_contains.append(output)
|
||||
if not output['actual'] == 'stdout':
|
||||
# Clean up file from previous tests, if any
|
||||
if os.path.exists(output['actual']):
|
||||
os.remove(output['actual'])
|
||||
# Create the parent directory for the file if it doesn't exist.
|
||||
filedir = os.path.dirname(output['actual'])
|
||||
if not os.path.isdir(filedir):
|
||||
os.makedirs(filedir)
|
||||
self.output_strictly_contains = output_strictly_contains
|
||||
|
||||
self.grpcurl_res = None
|
||||
self.grpc_observer = None
|
||||
self.grpc_address = self.params.get(
|
||||
'address', 'grpc/*', default='/var/run/falco.sock')
|
||||
self.grpc_address = self.params.get('address', 'grpc/*', default='/var/run/falco.sock')
|
||||
if self.grpc_address.startswith("unix://"):
|
||||
self.is_grpc_using_unix_socket = True
|
||||
self.grpc_address = self.grpc_address[len("unix://"):]
|
||||
@@ -249,22 +211,21 @@ class FalcoTest(Test):
|
||||
self.grpc_results = self.params.get('results', 'grpc/*', default='')
|
||||
if self.grpc_results == '':
|
||||
self.grpc_results = []
|
||||
else:
|
||||
else:
|
||||
if type(self.grpc_results) == str:
|
||||
self.grpc_results = [self.grpc_results]
|
||||
|
||||
self.disable_tags = self.params.get('disable_tags', '*', default='')
|
||||
|
||||
if self.disable_tags == '':
|
||||
self.disable_tags = []
|
||||
self.disable_tags=[]
|
||||
|
||||
self.run_tags = self.params.get('run_tags', '*', default='')
|
||||
|
||||
if self.run_tags == '':
|
||||
self.run_tags = []
|
||||
self.run_tags=[]
|
||||
|
||||
self.time_iso_8601 = self.params.get(
|
||||
'time_iso_8601', '*', default=False)
|
||||
self.time_iso_8601 = self.params.get('time_iso_8601', '*', default=False)
|
||||
|
||||
def tearDown(self):
|
||||
if self.package != 'None':
|
||||
@@ -283,8 +244,7 @@ class FalcoTest(Test):
|
||||
self.log.debug("Actual warning rules: {}".format(found_warning))
|
||||
|
||||
if found_warning != self.rules_warning:
|
||||
self.fail("Expected rules with warnings {} does not match actual rules with warnings {}".format(
|
||||
self.rules_warning, found_warning))
|
||||
self.fail("Expected rules with warnings {} does not match actual rules with warnings {}".format(self.rules_warning, found_warning))
|
||||
|
||||
def check_rules_events(self, res):
|
||||
|
||||
@@ -295,60 +255,50 @@ class FalcoTest(Test):
|
||||
events = set(match.group(2).split(","))
|
||||
found_events[rule] = events
|
||||
|
||||
self.log.debug(
|
||||
"Expected events for rules: {}".format(self.rules_events))
|
||||
self.log.debug("Expected events for rules: {}".format(self.rules_events))
|
||||
self.log.debug("Actual events for rules: {}".format(found_events))
|
||||
|
||||
for rule in list(found_events.keys()):
|
||||
if found_events.get(rule) != self.rules_events.get(rule):
|
||||
self.fail("rule {}: expected events {} differs from actual events {}".format(
|
||||
rule, self.rules_events.get(rule), found_events.get(rule)))
|
||||
self.fail("rule {}: expected events {} differs from actual events {}".format(rule, self.rules_events.get(rule), found_events.get(rule)))
|
||||
|
||||
def check_detections(self, res):
|
||||
# Get the number of events detected.
|
||||
match = re.search('Events detected: (\d+)', res.stdout.decode("utf-8"))
|
||||
if match is None:
|
||||
self.fail(
|
||||
"Could not find a line 'Events detected: <count>' in falco output")
|
||||
self.fail("Could not find a line 'Events detected: <count>' in falco output")
|
||||
|
||||
events_detected = int(match.group(1))
|
||||
|
||||
if not self.should_detect and events_detected > 0:
|
||||
self.fail("Detected {} events when should have detected none".format(
|
||||
events_detected))
|
||||
self.fail("Detected {} events when should have detected none".format(events_detected))
|
||||
|
||||
if self.should_detect:
|
||||
if events_detected == 0:
|
||||
self.fail("Detected {} events when should have detected > 0".format(
|
||||
events_detected))
|
||||
self.fail("Detected {} events when should have detected > 0".format(events_detected))
|
||||
|
||||
for level in self.detect_level:
|
||||
level_line = '(?i){}: (\d+)'.format(level)
|
||||
match = re.search(level_line, res.stdout.decode("utf-8"))
|
||||
|
||||
if match is None:
|
||||
self.fail(
|
||||
"Could not find a line '{}: <count>' in falco output".format(level))
|
||||
self.fail("Could not find a line '{}: <count>' in falco output".format(level))
|
||||
|
||||
events_detected = int(match.group(1))
|
||||
|
||||
if not events_detected > 0:
|
||||
self.fail("Detected {} events at level {} when should have detected > 0".format(
|
||||
events_detected, level))
|
||||
self.fail("Detected {} events at level {} when should have detected > 0".format(events_detected, level))
|
||||
|
||||
def check_detections_by_rule(self, res):
|
||||
# Get the number of events detected for each rule. Must match the expected counts.
|
||||
match = re.search('Triggered rules by rule name:(.*)',
|
||||
res.stdout.decode("utf-8"), re.DOTALL)
|
||||
match = re.search('Triggered rules by rule name:(.*)', res.stdout.decode("utf-8"), re.DOTALL)
|
||||
if match is None:
|
||||
self.fail(
|
||||
"Could not find a block 'Triggered rules by rule name: ...' in falco output")
|
||||
self.fail("Could not find a block 'Triggered rules by rule name: ...' in falco output")
|
||||
|
||||
triggered_rules = match.group(1)
|
||||
|
||||
for rule, count in list(self.detect_counts.items()):
|
||||
expected = '\s{}: (\d+)'.format(
|
||||
re.sub(r'([$\.*+?()[\]{}|^])', r'\\\1', rule))
|
||||
expected = '\s{}: (\d+)'.format(re.sub(r'([$\.*+?()[\]{}|^])', r'\\\1', rule))
|
||||
match = re.search(expected, triggered_rules)
|
||||
|
||||
if match is None:
|
||||
@@ -357,11 +307,9 @@ class FalcoTest(Test):
|
||||
actual_count = int(match.group(1))
|
||||
|
||||
if actual_count != count:
|
||||
self.fail("Different counts for rule {}: expected={}, actual={}".format(
|
||||
rule, count, actual_count))
|
||||
self.fail("Different counts for rule {}: expected={}, actual={}".format(rule, count, actual_count))
|
||||
else:
|
||||
self.log.debug(
|
||||
"Found expected count for rule {}: {}".format(rule, count))
|
||||
self.log.debug("Found expected count for rule {}: {}".format(rule, count))
|
||||
|
||||
def check_outputs(self):
|
||||
for output in self.outputs:
|
||||
@@ -376,8 +324,7 @@ class FalcoTest(Test):
|
||||
found = True
|
||||
|
||||
if found == False:
|
||||
self.fail("Could not find a line '{}' in file '{}'".format(
|
||||
output['line'], output['file']))
|
||||
self.fail("Could not find a line '{}' in file '{}'".format(output['line'], output['file']))
|
||||
|
||||
return True
|
||||
|
||||
@@ -394,27 +341,7 @@ class FalcoTest(Test):
|
||||
attrs = ['time', 'rule', 'priority']
|
||||
for attr in attrs:
|
||||
if not attr in obj:
|
||||
self.fail(
|
||||
"Falco JSON object {} does not contain property \"{}\"".format(line, attr))
|
||||
|
||||
def check_output_strictly_contains(self, res):
|
||||
for output in self.output_strictly_contains:
|
||||
# Read the expected output (from a file) and actual output (either from a file or the stdout),
|
||||
# then check if the actual one strictly contains the expected one.
|
||||
|
||||
expected = open(output['expected']).read()
|
||||
|
||||
if output['actual'] == 'stdout':
|
||||
actual = res.stdout.decode("utf-8")
|
||||
else:
|
||||
actual = open(output['actual']).read()
|
||||
|
||||
if expected not in actual:
|
||||
self.fail("Output '{}' does not strictly contains the expected content '{}'".format(
|
||||
output['actual'], output['expected']))
|
||||
return False
|
||||
|
||||
return True
|
||||
self.fail("Falco JSON object {} does not contain property \"{}\"".format(line, attr))
|
||||
|
||||
def install_package(self):
|
||||
|
||||
@@ -433,39 +360,35 @@ class FalcoTest(Test):
|
||||
self.module_dir, self.addl_docker_run_args, image)
|
||||
|
||||
elif self.package.endswith(".deb"):
|
||||
self.falco_binary_path = '/usr/bin/falco'
|
||||
self.falco_binary_path = '/usr/bin/falco';
|
||||
|
||||
package_glob = "{}/{}".format(self.falcodir, self.package)
|
||||
|
||||
matches = glob.glob(package_glob)
|
||||
|
||||
if len(matches) != 1:
|
||||
self.fail("Package path {} did not match exactly 1 file. Instead it matched: {}",
|
||||
package_glob, ",".join(matches))
|
||||
self.fail("Package path {} did not match exactly 1 file. Instead it matched: {}", package_glob, ",".join(matches))
|
||||
|
||||
package_path = matches[0]
|
||||
|
||||
cmdline = "dpkg -i {}".format(package_path)
|
||||
self.log.debug(
|
||||
"Installing debian package via \"{}\"".format(cmdline))
|
||||
self.log.debug("Installing debian package via \"{}\"".format(cmdline))
|
||||
res = process.run(cmdline, timeout=120, sudo=True)
|
||||
|
||||
elif self.package.endswith(".rpm"):
|
||||
self.falco_binary_path = '/usr/bin/falco'
|
||||
self.falco_binary_path = '/usr/bin/falco';
|
||||
|
||||
package_glob = "{}/{}".format(self.falcodir, self.package)
|
||||
|
||||
matches = glob.glob(package_glob)
|
||||
|
||||
if len(matches) != 1:
|
||||
self.fail("Package path {} did not match exactly 1 file. Instead it matched: {}",
|
||||
package_glob, ",".join(matches))
|
||||
self.fail("Package path {} did not match exactly 1 file. Instead it matched: {}", package_glob, ",".join(matches))
|
||||
|
||||
package_path = matches[0]
|
||||
|
||||
cmdline = "rpm -i --nodeps --noscripts {}".format(package_path)
|
||||
self.log.debug(
|
||||
"Installing centos package via \"{}\"".format(cmdline))
|
||||
self.log.debug("Installing centos package via \"{}\"".format(cmdline))
|
||||
res = process.run(cmdline, timeout=120, sudo=True)
|
||||
|
||||
def uninstall_package(self):
|
||||
@@ -475,29 +398,25 @@ class FalcoTest(Test):
|
||||
|
||||
elif self.package.endswith(".rpm"):
|
||||
cmdline = "rpm -e --noscripts --nodeps falco"
|
||||
self.log.debug(
|
||||
"Uninstalling centos package via \"{}\"".format(cmdline))
|
||||
self.log.debug("Uninstalling centos package via \"{}\"".format(cmdline))
|
||||
res = process.run(cmdline, timeout=120, sudo=True)
|
||||
|
||||
elif self.package.endswith(".deb"):
|
||||
cmdline = "dpkg --purge falco"
|
||||
self.log.debug(
|
||||
"Uninstalling debian package via \"{}\"".format(cmdline))
|
||||
self.log.debug("Uninstalling debian package via \"{}\"".format(cmdline))
|
||||
res = process.run(cmdline, timeout=120, sudo=True)
|
||||
|
||||
def possibly_copy_driver(self):
|
||||
# Remove the contents of ~/.falco regardless of copy_local_driver.
|
||||
self.log.debug("Checking for module dir {}".format(self.module_dir))
|
||||
if os.path.isdir(self.module_dir):
|
||||
self.log.info(
|
||||
"Removing files below directory {}".format(self.module_dir))
|
||||
self.log.info("Removing files below directory {}".format(self.module_dir))
|
||||
for rmfile in glob.glob(self.module_dir + "/*"):
|
||||
self.log.debug("Removing file {}".format(rmfile))
|
||||
os.remove(rmfile)
|
||||
|
||||
if self.copy_local_driver:
|
||||
verlines = [str.strip() for str in subprocess.check_output(
|
||||
[self.falco_binary_path, "--version"]).splitlines()]
|
||||
verlines = [str.strip() for str in subprocess.check_output([self.falco_binary_path, "--version"]).splitlines()]
|
||||
verstr = verlines[0].decode("utf-8")
|
||||
self.log.info("verstr {}".format(verstr))
|
||||
falco_version = verstr.split(" ")[2]
|
||||
@@ -509,12 +428,10 @@ class FalcoTest(Test):
|
||||
|
||||
# falco-driver-loader has a more comprehensive set of ways to
|
||||
# find the config hash. We only look at /boot/config-<kernel release>
|
||||
md5_output = subprocess.check_output(
|
||||
["md5sum", "/boot/config-{}".format(kernel_release)]).rstrip()
|
||||
md5_output = subprocess.check_output(["md5sum", "/boot/config-{}".format(kernel_release)]).rstrip()
|
||||
config_hash = md5_output.split(" ")[0]
|
||||
|
||||
probe_filename = "falco-{}-{}-{}-{}.ko".format(
|
||||
falco_version, arch, kernel_release, config_hash)
|
||||
probe_filename = "falco-{}-{}-{}-{}.ko".format(falco_version, arch, kernel_release, config_hash)
|
||||
driver_path = os.path.join(self.falcodir, "driver", "falco.ko")
|
||||
module_path = os.path.join(self.module_dir, probe_filename)
|
||||
self.log.debug("Copying {} to {}".format(driver_path, module_path))
|
||||
@@ -525,22 +442,20 @@ class FalcoTest(Test):
|
||||
if len(self.grpc_results) > 0:
|
||||
if not self.is_grpc_using_unix_socket:
|
||||
self.fail("This test suite supports gRPC with unix socket only")
|
||||
|
||||
cmdline = "grpcurl -format text -import-path ../userspace/falco " \
|
||||
"-proto {} -plaintext -unix {} " \
|
||||
"{}/{}".format(self.grpc_proto, self.grpc_address,
|
||||
self.grpc_service, self.grpc_method)
|
||||
|
||||
cmdline = "grpcurl -import-path ../userspace/falco " \
|
||||
"-proto {} -plaintext -unix {} " \
|
||||
"{}/{}".format(self.grpc_proto, self.grpc_address, self.grpc_service, self.grpc_method)
|
||||
that = self
|
||||
|
||||
class GRPCUnixSocketEventHandler(PatternMatchingEventHandler):
|
||||
def on_created(self, event):
|
||||
# that.log.info("EVENT: {}", event)
|
||||
that.grpcurl_res = process.run(cmdline)
|
||||
|
||||
|
||||
path = os.path.dirname(self.grpc_address)
|
||||
process.run("mkdir -p {}".format(path))
|
||||
event_handler = GRPCUnixSocketEventHandler(patterns=['*'],
|
||||
ignore_directories=True)
|
||||
ignore_directories=True)
|
||||
self.grpc_observer = Observer()
|
||||
self.grpc_observer.schedule(event_handler, path, recursive=False)
|
||||
self.grpc_observer.start()
|
||||
@@ -555,19 +470,19 @@ class FalcoTest(Test):
|
||||
for exp_result in self.grpc_results:
|
||||
found = False
|
||||
for line in self.grpcurl_res.stdout.decode("utf-8").splitlines():
|
||||
if exp_result in line:
|
||||
match = re.search(exp_result, line)
|
||||
|
||||
if match is not None:
|
||||
found = True
|
||||
break
|
||||
|
||||
if found == False:
|
||||
self.fail(
|
||||
"Could not find a line with '{}' in gRPC responses (protobuf text".format(exp_result))
|
||||
self.fail("Could not find a line '{}' in gRPC responses".format(exp_result))
|
||||
|
||||
|
||||
def test(self):
|
||||
self.log.info("Trace file %s", self.trace_file)
|
||||
|
||||
self.falco_binary_path = '{}/userspace/falco/falco'.format(
|
||||
self.falcodir)
|
||||
self.falco_binary_path = '{}/userspace/falco/falco'.format(self.falcodir)
|
||||
|
||||
self.possibly_copy_driver()
|
||||
|
||||
@@ -586,11 +501,9 @@ class FalcoTest(Test):
|
||||
if self.psp_file != "":
|
||||
|
||||
if not os.path.isfile(self.psp_conv_path):
|
||||
self.log.info("Downloading {} to {}".format(
|
||||
self.psp_conv_url, self.psp_conv_path))
|
||||
self.log.info("Downloading {} to {}".format(self.psp_conv_url, self.psp_conv_path))
|
||||
|
||||
urllib.request.urlretrieve(
|
||||
self.psp_conv_url, self.psp_conv_path)
|
||||
urllib.request.urlretrieve(self.psp_conv_url, self.psp_conv_path)
|
||||
os.chmod(self.psp_conv_path, stat.S_IEXEC)
|
||||
|
||||
conv_cmd = '{} convert psp --psp-path {} --rules-path {}'.format(
|
||||
@@ -608,6 +521,7 @@ class FalcoTest(Test):
|
||||
psp_rules = myfile.read()
|
||||
self.log.debug("Converted Rules: {}".format(psp_rules))
|
||||
|
||||
|
||||
# Run falco
|
||||
cmd = '{} {} {} -c {} {} -o json_output={} -o json_include_output_property={} -o priority={} -v'.format(
|
||||
self.falco_binary_path, self.rules_args, self.disabled_args, self.conf_file, trace_arg, self.json_output, self.json_include_output_property, self.priority)
|
||||
@@ -643,26 +557,22 @@ class FalcoTest(Test):
|
||||
for pattern in self.stderr_contains:
|
||||
match = re.search(pattern, res.stderr.decode("utf-8"))
|
||||
if match is None:
|
||||
self.fail(
|
||||
"Stderr of falco process did not contain content matching {}".format(pattern))
|
||||
self.fail("Stderr of falco process did not contain content matching {}".format(pattern))
|
||||
|
||||
for pattern in self.stdout_contains:
|
||||
match = re.search(pattern, res.stdout.decode("utf-8"))
|
||||
if match is None:
|
||||
self.fail("Stdout of falco process '{}' did not contain content matching {}".format(
|
||||
res.stdout.decode("utf-8"), pattern))
|
||||
self.fail("Stdout of falco process '{}' did not contain content matching {}".format(res.stdout.decode("utf-8"), pattern))
|
||||
|
||||
for pattern in self.stderr_not_contains:
|
||||
match = re.search(pattern, res.stderr.decode("utf-8"))
|
||||
if match is not None:
|
||||
self.fail(
|
||||
"Stderr of falco process contained content matching {} when it should have not".format(pattern))
|
||||
self.fail("Stderr of falco process contained content matching {} when it should have not".format(pattern))
|
||||
|
||||
for pattern in self.stdout_not_contains:
|
||||
match = re.search(pattern, res.stdout.decode("utf-8"))
|
||||
if match is not None:
|
||||
self.fail("Stdout of falco process '{}' did contain content matching {} when it should have not".format(
|
||||
res.stdout.decode("utf-8"), pattern))
|
||||
self.fail("Stdout of falco process '{}' did contain content matching {} when it should have not".format(res.stdout.decode("utf-8"), pattern))
|
||||
|
||||
if res.exit_status != self.exit_status:
|
||||
self.error("Falco command \"{}\" exited with unexpected return value {} (!= {})".format(
|
||||
@@ -680,7 +590,6 @@ class FalcoTest(Test):
|
||||
self.check_detections_by_rule(res)
|
||||
self.check_json_output(res)
|
||||
self.check_outputs()
|
||||
self.check_output_strictly_contains(res)
|
||||
self.check_grpc()
|
||||
pass
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
# Copyright (C) 2016-2018 The Falco Authors..
|
||||
#
|
||||
# This file is part of falco.
|
||||
#
|
||||
@@ -652,50 +652,25 @@ trace_files: !mux
|
||||
trace_file: trace_files/cat_write.scap
|
||||
stdout_contains: "Warning An open was seen .cport=<NA> command=cat /dev/null."
|
||||
|
||||
stdout_output_strict:
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/single_rule.yaml
|
||||
conf_file: confs/stdout_output.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
time_iso_8601: true
|
||||
output_strictly_contains:
|
||||
- stdout: output_files/single_rule_with_cat_write.txt
|
||||
|
||||
stdout_output_json_strict:
|
||||
json_output: True
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/single_rule.yaml
|
||||
conf_file: confs/stdout_output.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
time_iso_8601: true
|
||||
output_strictly_contains:
|
||||
- stdout: output_files/single_rule_with_cat_write.json
|
||||
|
||||
file_output_strict:
|
||||
file_output:
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/single_rule.yaml
|
||||
conf_file: confs/file_output.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
time_iso_8601: true
|
||||
output_strictly_contains:
|
||||
- /tmp/falco_outputs/file_output.txt: output_files/single_rule_with_cat_write.txt
|
||||
outputs:
|
||||
- /tmp/falco_outputs/file_output.txt: Warning An open was seen
|
||||
|
||||
program_output_strict:
|
||||
program_output:
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/single_rule.yaml
|
||||
conf_file: confs/program_output.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
time_iso_8601: true
|
||||
output_strictly_contains:
|
||||
- /tmp/falco_outputs/program_output.txt: output_files/single_rule_with_cat_write.txt
|
||||
outputs:
|
||||
- /tmp/falco_outputs/program_output.txt: Warning An open was seen
|
||||
|
||||
grpc_unix_socket_outputs:
|
||||
detect: True
|
||||
@@ -705,26 +680,13 @@ trace_files: !mux
|
||||
conf_file: confs/grpc_unix_socket.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
run_duration: 5
|
||||
time_iso_8601: true
|
||||
grpc:
|
||||
address: unix:///tmp/falco/falco.sock
|
||||
proto: outputs.proto
|
||||
service: falco.outputs.service
|
||||
method: get
|
||||
# protobuf text format
|
||||
results:
|
||||
- "seconds:1470327477 nanos:881781397"
|
||||
- "priority: WARNING"
|
||||
- "rule: \"open_from_cat\""
|
||||
- "output: \"2016-08-04T16:17:57.881781397+0000: Warning An open was seen (command=cat /dev/null)\""
|
||||
# output fields
|
||||
- "key: \"evt.time.iso8601\""
|
||||
- "value: \"2016-08-04T16:17:57.881781397+0000\""
|
||||
- "key: \"proc.cmdline\""
|
||||
- "value: \"cat /dev/null\""
|
||||
# For the hostname, since we don't know that beforehand,
|
||||
# only check the field presence
|
||||
- "hostname: "
|
||||
- "Warning An open was seen"
|
||||
|
||||
detect_counts:
|
||||
detect: True
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
{"output":"2016-08-04T16:17:57.881781397+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.881781397Z", "output_fields": {"evt.time.iso8601":1470327477881781397,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.881785348+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.881785348Z", "output_fields": {"evt.time.iso8601":1470327477881785348,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.881796705+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.881796705Z", "output_fields": {"evt.time.iso8601":1470327477881796705,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.881799840+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.881799840Z", "output_fields": {"evt.time.iso8601":1470327477881799840,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.882003104+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.882003104Z", "output_fields": {"evt.time.iso8601":1470327477882003104,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.882008208+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.882008208Z", "output_fields": {"evt.time.iso8601":1470327477882008208,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.882045694+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.882045694Z", "output_fields": {"evt.time.iso8601":1470327477882045694,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.882054739+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.882054739Z", "output_fields": {"evt.time.iso8601":1470327477882054739,"proc.cmdline":"cat /dev/null"}}
|
||||
@@ -1,8 +0,0 @@
|
||||
2016-08-04T16:17:57.881781397+0000: Warning An open was seen (command=cat /dev/null)
|
||||
2016-08-04T16:17:57.881785348+0000: Warning An open was seen (command=cat /dev/null)
|
||||
2016-08-04T16:17:57.881796705+0000: Warning An open was seen (command=cat /dev/null)
|
||||
2016-08-04T16:17:57.881799840+0000: Warning An open was seen (command=cat /dev/null)
|
||||
2016-08-04T16:17:57.882003104+0000: Warning An open was seen (command=cat /dev/null)
|
||||
2016-08-04T16:17:57.882008208+0000: Warning An open was seen (command=cat /dev/null)
|
||||
2016-08-04T16:17:57.882045694+0000: Warning An open was seen (command=cat /dev/null)
|
||||
2016-08-04T16:17:57.882054739+0000: Warning An open was seen (command=cat /dev/null)
|
||||
@@ -18,5 +18,5 @@
|
||||
desc: Detect any connect to the localhost network, using fd.net and the in operator
|
||||
condition: evt.type=connect and fd.net in ("127.0.0.1/24")
|
||||
output: Program connected to localhost network
|
||||
(user=%user.name user_loginuid=%user.loginuid command=%proc.cmdline connection=%fd.name)
|
||||
(user=%user.name command=%proc.cmdline connection=%fd.name)
|
||||
priority: INFO
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
- macro: allowed_k8s_containers
|
||||
condition: (ka.req.pod.containers.image.repository in (nginx))
|
||||
|
||||
|
||||
@@ -19,13 +19,6 @@ set -euo pipefail
|
||||
|
||||
SCRIPT=$(readlink -f $0)
|
||||
SCRIPTDIR=$(dirname "$SCRIPT")
|
||||
SKIP_PACKAGES_TESTS=${SKIP_PACKAGES_TESTS:-false}
|
||||
|
||||
# Trace file tarballs are now versioned. Any time a substantial change
|
||||
# is made that affects the interaction of rules+engine and the trace
|
||||
# files here, upload a new trace file zip file and change the version
|
||||
# suffix here.
|
||||
TRACE_FILES_VERSION=20200831
|
||||
|
||||
function download_trace_files() {
|
||||
for TRACE in traces-positive traces-negative traces-info ; do
|
||||
@@ -33,7 +26,7 @@ function download_trace_files() {
|
||||
if [ "$OPT_BRANCH" != "none" ]; then
|
||||
curl -fso "$TRACE_DIR/$TRACE.zip" https://s3.amazonaws.com/download.draios.com/falco-tests/$TRACE-$OPT_BRANCH.zip
|
||||
else
|
||||
curl -fso "$TRACE_DIR/$TRACE.zip" https://s3.amazonaws.com/download.draios.com/falco-tests/$TRACE-$TRACE_FILES_VERSION.zip
|
||||
curl -fso "$TRACE_DIR/$TRACE.zip" https://s3.amazonaws.com/download.draios.com/falco-tests/$TRACE.zip
|
||||
fi
|
||||
unzip -d "$TRACE_DIR" "$TRACE_DIR/$TRACE.zip"
|
||||
rm -rf "$TRACE_DIR/$TRACE.zip"
|
||||
@@ -98,18 +91,8 @@ function run_tests() {
|
||||
# as we're watching the return status when running avocado.
|
||||
set +e
|
||||
TEST_RC=0
|
||||
suites=($SCRIPTDIR/falco_traces.yaml $SCRIPTDIR/falco_tests.yaml $SCRIPTDIR/falco_k8s_audit_tests.yaml $SCRIPTDIR/falco_tests_psp.yaml)
|
||||
|
||||
if [ "$SKIP_PACKAGES_TESTS" = false ] ; then
|
||||
suites+=($SCRIPTDIR/falco_tests_package.yaml)
|
||||
fi
|
||||
|
||||
XUNIT_DIR="${OPT_BUILD_DIR}/integration-tests-xunit"
|
||||
mkdir -p "${XUNIT_DIR}"
|
||||
|
||||
for mult in "${suites[@]}"; do
|
||||
XUNIT_FILE_NAME="${XUNIT_DIR}/$(basename "${mult}").xml"
|
||||
CMD="avocado run --xunit ${XUNIT_FILE_NAME} --mux-yaml $mult --job-results-dir $SCRIPTDIR/job-results -- $SCRIPTDIR/falco_test.py"
|
||||
for mult in $SCRIPTDIR/falco_traces.yaml $SCRIPTDIR/falco_tests.yaml $SCRIPTDIR/falco_tests_package.yaml $SCRIPTDIR/falco_k8s_audit_tests.yaml $SCRIPTDIR/falco_tests_psp.yaml; do
|
||||
CMD="avocado run --mux-yaml $mult --job-results-dir $SCRIPTDIR/job-results -- $SCRIPTDIR/falco_test.py"
|
||||
echo "Running $CMD"
|
||||
BUILD_DIR=${OPT_BUILD_DIR} $CMD
|
||||
RC=$?
|
||||
|
||||
@@ -14,11 +14,7 @@
|
||||
# License for the specific language governing permissions and limitations under
|
||||
# the License.
|
||||
#
|
||||
if(MINIMAL_BUILD)
|
||||
set(FALCO_TESTS_SOURCES test_base.cpp engine/test_token_bucket.cpp engine/test_rulesets.cpp engine/test_falco_utils.cpp)
|
||||
else()
|
||||
set(FALCO_TESTS_SOURCES test_base.cpp engine/test_token_bucket.cpp engine/test_rulesets.cpp engine/test_falco_utils.cpp falco/test_webserver.cpp)
|
||||
endif()
|
||||
set(FALCO_TESTS_SOURCES test_base.cpp engine/test_token_bucket.cpp engine/test_rulesets.cpp engine/test_falco_utils.cpp falco/test_webserver.cpp)
|
||||
|
||||
set(FALCO_TESTED_LIBRARIES falco_engine)
|
||||
|
||||
@@ -39,25 +35,14 @@ if(FALCO_BUILD_TESTS)
|
||||
add_executable(falco_test ${FALCO_TESTS_SOURCES})
|
||||
|
||||
target_link_libraries(falco_test PUBLIC ${FALCO_TESTED_LIBRARIES})
|
||||
|
||||
if(MINIMAL_BUILD)
|
||||
target_include_directories(
|
||||
falco_test
|
||||
PUBLIC "${CATCH2_INCLUDE}"
|
||||
"${FAKEIT_INCLUDE}"
|
||||
"${PROJECT_SOURCE_DIR}/userspace/engine"
|
||||
"${YAMLCPP_INCLUDE_DIR}"
|
||||
"${PROJECT_SOURCE_DIR}/userspace/falco")
|
||||
else()
|
||||
target_include_directories(
|
||||
falco_test
|
||||
PUBLIC "${CATCH2_INCLUDE}"
|
||||
"${FAKEIT_INCLUDE}"
|
||||
"${PROJECT_SOURCE_DIR}/userspace/engine"
|
||||
"${YAMLCPP_INCLUDE_DIR}"
|
||||
"${CIVETWEB_INCLUDE_DIR}"
|
||||
"${PROJECT_SOURCE_DIR}/userspace/falco")
|
||||
endif()
|
||||
target_include_directories(
|
||||
falco_test
|
||||
PUBLIC "${CATCH2_INCLUDE}"
|
||||
"${FAKEIT_INCLUDE}"
|
||||
"${PROJECT_SOURCE_DIR}/userspace/engine"
|
||||
"${YAMLCPP_INCLUDE_DIR}"
|
||||
"${CIVETWEB_INCLUDE_DIR}"
|
||||
"${PROJECT_SOURCE_DIR}/userspace/falco")
|
||||
add_dependencies(falco_test catch2)
|
||||
|
||||
include(CMakeParseArguments)
|
||||
|
||||
@@ -27,32 +27,18 @@ if(USE_BUNDLED_DEPS)
|
||||
add_dependencies(falco_engine libyaml)
|
||||
endif()
|
||||
|
||||
if(MINIMAL_BUILD)
|
||||
target_include_directories(
|
||||
falco_engine
|
||||
PUBLIC
|
||||
"${LUAJIT_INCLUDE}"
|
||||
"${NJSON_INCLUDE}"
|
||||
"${TBB_INCLUDE_DIR}"
|
||||
"${STRING_VIEW_LITE_INCLUDE}"
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/libsinsp/third-party/jsoncpp"
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/libscap"
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/libsinsp"
|
||||
"${PROJECT_BINARY_DIR}/userspace/engine")
|
||||
else()
|
||||
target_include_directories(
|
||||
falco_engine
|
||||
PUBLIC
|
||||
"${LUAJIT_INCLUDE}"
|
||||
"${NJSON_INCLUDE}"
|
||||
"${CURL_INCLUDE_DIR}"
|
||||
"${TBB_INCLUDE_DIR}"
|
||||
"${STRING_VIEW_LITE_INCLUDE}"
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/libsinsp/third-party/jsoncpp"
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/libscap"
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/libsinsp"
|
||||
"${PROJECT_BINARY_DIR}/userspace/engine")
|
||||
endif()
|
||||
target_include_directories(
|
||||
falco_engine
|
||||
PUBLIC
|
||||
"${LUAJIT_INCLUDE}"
|
||||
"${NJSON_INCLUDE}"
|
||||
"${CURL_INCLUDE_DIR}"
|
||||
"${TBB_INCLUDE_DIR}"
|
||||
"${STRING_VIEW_LITE_INCLUDE}"
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/libsinsp/third-party/jsoncpp"
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/libscap"
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/libsinsp"
|
||||
"${PROJECT_BINARY_DIR}/userspace/engine")
|
||||
|
||||
target_link_libraries(falco_engine "${FALCO_SINSP_LIBRARY}" "${LPEG_LIB}" "${LYAML_LIB}" "${LIBYAML_LIB}")
|
||||
|
||||
|
||||
@@ -171,8 +171,9 @@ void falco_engine::load_rules(const string &rules_content, bool verbose, bool al
|
||||
m_ls);
|
||||
}
|
||||
|
||||
// Note that falco_formats is added to the lua state used
|
||||
// by the falco engine only. Within the engine, only
|
||||
// Note that falco_formats is added to both the lua state used
|
||||
// by the falco engine as well as the separate lua state used
|
||||
// by falco outputs. Within the engine, only
|
||||
// formats.formatter is used, so we can unconditionally set
|
||||
// json_output to false.
|
||||
bool json_output = false;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
Copyright (C) 2019 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.
|
||||
@@ -16,7 +16,7 @@ limitations under the License.
|
||||
|
||||
// The version of rules/filter fields/etc supported by this falco
|
||||
// engine.
|
||||
#define FALCO_ENGINE_VERSION (7)
|
||||
#define FALCO_ENGINE_VERSION (6)
|
||||
|
||||
// This is the result of running "falco --list -N | sha256sum" and
|
||||
// represents the fields supported by this version of falco. It's used
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
Copyright (C) 2019 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.
|
||||
@@ -20,19 +20,24 @@ limitations under the License.
|
||||
#include "falco_engine.h"
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
sinsp *falco_formats::s_inspector = NULL;
|
||||
|
||||
sinsp* falco_formats::s_inspector = NULL;
|
||||
falco_engine *falco_formats::s_engine = NULL;
|
||||
bool falco_formats::s_json_output = false;
|
||||
bool falco_formats::s_json_include_output_property = true;
|
||||
std::unique_ptr<sinsp_evt_formatter_cache> falco_formats::s_formatters = NULL;
|
||||
sinsp_evt_formatter_cache *falco_formats::s_formatters = NULL;
|
||||
|
||||
const static struct luaL_Reg ll_falco[] =
|
||||
{
|
||||
{"formatter", &falco_formats::lua_formatter},
|
||||
{"free_formatter", &falco_formats::lua_free_formatter},
|
||||
{NULL, NULL}};
|
||||
const static struct luaL_reg ll_falco [] =
|
||||
{
|
||||
{"formatter", &falco_formats::formatter},
|
||||
{"free_formatter", &falco_formats::free_formatter},
|
||||
{"free_formatters", &falco_formats::free_formatters},
|
||||
{"format_event", &falco_formats::format_event},
|
||||
{"resolve_tokens", &falco_formats::resolve_tokens},
|
||||
{NULL,NULL}
|
||||
};
|
||||
|
||||
void falco_formats::init(sinsp *inspector,
|
||||
void falco_formats::init(sinsp* inspector,
|
||||
falco_engine *engine,
|
||||
lua_State *ls,
|
||||
bool json_output,
|
||||
@@ -42,14 +47,15 @@ void falco_formats::init(sinsp *inspector,
|
||||
s_engine = engine;
|
||||
s_json_output = json_output;
|
||||
s_json_include_output_property = json_include_output_property;
|
||||
|
||||
// todo(leogr): we should have used std::make_unique, but we cannot since it's not C++14
|
||||
s_formatters = std::unique_ptr<sinsp_evt_formatter_cache>(new sinsp_evt_formatter_cache(s_inspector));
|
||||
if(!s_formatters)
|
||||
{
|
||||
s_formatters = new sinsp_evt_formatter_cache(s_inspector);
|
||||
}
|
||||
|
||||
luaL_openlib(ls, "formats", ll_falco, 0);
|
||||
}
|
||||
|
||||
int falco_formats::lua_formatter(lua_State *ls)
|
||||
int falco_formats::formatter(lua_State *ls)
|
||||
{
|
||||
string source = luaL_checkstring(ls, -2);
|
||||
string format = luaL_checkstring(ls, -1);
|
||||
@@ -58,7 +64,7 @@ int falco_formats::lua_formatter(lua_State *ls)
|
||||
{
|
||||
if(source == "syscall")
|
||||
{
|
||||
sinsp_evt_formatter *formatter;
|
||||
sinsp_evt_formatter* formatter;
|
||||
formatter = new sinsp_evt_formatter(s_inspector, format);
|
||||
lua_pushlightuserdata(ls, formatter);
|
||||
}
|
||||
@@ -69,11 +75,11 @@ int falco_formats::lua_formatter(lua_State *ls)
|
||||
lua_pushlightuserdata(ls, formatter);
|
||||
}
|
||||
}
|
||||
catch(sinsp_exception &e)
|
||||
catch(sinsp_exception& e)
|
||||
{
|
||||
luaL_error(ls, "Invalid output format '%s': '%s'", format.c_str(), e.what());
|
||||
}
|
||||
catch(falco_exception &e)
|
||||
catch(falco_exception& e)
|
||||
{
|
||||
luaL_error(ls, "Invalid output format '%s': '%s'", format.c_str(), e.what());
|
||||
}
|
||||
@@ -81,10 +87,10 @@ int falco_formats::lua_formatter(lua_State *ls)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int falco_formats::lua_free_formatter(lua_State *ls)
|
||||
int falco_formats::free_formatter(lua_State *ls)
|
||||
{
|
||||
if(!lua_islightuserdata(ls, -1) ||
|
||||
!lua_isstring(ls, -2))
|
||||
if (!lua_islightuserdata(ls, -1) ||
|
||||
!lua_isstring(ls, -2))
|
||||
|
||||
{
|
||||
luaL_error(ls, "Invalid argument passed to free_formatter");
|
||||
@@ -94,75 +100,115 @@ int falco_formats::lua_free_formatter(lua_State *ls)
|
||||
|
||||
if(source == "syscall")
|
||||
{
|
||||
sinsp_evt_formatter *formatter = (sinsp_evt_formatter *)lua_topointer(ls, -1);
|
||||
sinsp_evt_formatter *formatter = (sinsp_evt_formatter *) lua_topointer(ls, -1);
|
||||
delete(formatter);
|
||||
}
|
||||
else
|
||||
{
|
||||
json_event_formatter *formatter = (json_event_formatter *)lua_topointer(ls, -1);
|
||||
json_event_formatter *formatter = (json_event_formatter *) lua_topointer(ls, -1);
|
||||
delete(formatter);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
string falco_formats::format_event(const gen_event *evt, const std::string &rule, const std::string &source,
|
||||
const std::string &level, const std::string &format)
|
||||
int falco_formats::free_formatters(lua_State *ls)
|
||||
{
|
||||
if(s_formatters)
|
||||
{
|
||||
delete(s_formatters);
|
||||
s_formatters = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int falco_formats::format_event (lua_State *ls)
|
||||
{
|
||||
string line;
|
||||
string json_line;
|
||||
|
||||
if (!lua_isstring(ls, -1) ||
|
||||
!lua_isstring(ls, -2) ||
|
||||
!lua_isstring(ls, -3) ||
|
||||
!lua_isstring(ls, -4) ||
|
||||
!lua_islightuserdata(ls, -5)) {
|
||||
lua_pushstring(ls, "Invalid arguments passed to format_event()");
|
||||
lua_error(ls);
|
||||
}
|
||||
gen_event* evt = (gen_event*)lua_topointer(ls, 1);
|
||||
const char *rule = (char *) lua_tostring(ls, 2);
|
||||
const char *source = (char *) lua_tostring(ls, 3);
|
||||
const char *level = (char *) lua_tostring(ls, 4);
|
||||
const char *format = (char *) lua_tostring(ls, 5);
|
||||
|
||||
string sformat = format;
|
||||
|
||||
if(strcmp(source.c_str(), "syscall") == 0)
|
||||
if(strcmp(source, "syscall") == 0)
|
||||
{
|
||||
// This is "output"
|
||||
s_formatters->tostring((sinsp_evt *)evt, sformat, &line);
|
||||
try {
|
||||
// This is "output"
|
||||
s_formatters->tostring((sinsp_evt *) evt, sformat, &line);
|
||||
|
||||
if(s_json_output)
|
||||
if(s_json_output)
|
||||
{
|
||||
sinsp_evt::param_fmt cur_fmt = s_inspector->get_buffer_format();
|
||||
switch(cur_fmt)
|
||||
{
|
||||
case sinsp_evt::PF_NORMAL:
|
||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSON);
|
||||
break;
|
||||
case sinsp_evt::PF_EOLS:
|
||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSONEOLS);
|
||||
break;
|
||||
case sinsp_evt::PF_HEX:
|
||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSONHEX);
|
||||
break;
|
||||
case sinsp_evt::PF_HEXASCII:
|
||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSONHEXASCII);
|
||||
break;
|
||||
case sinsp_evt::PF_BASE64:
|
||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSONBASE64);
|
||||
break;
|
||||
default:
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
// This is output fields
|
||||
s_formatters->tostring((sinsp_evt *) evt, sformat, &json_line);
|
||||
|
||||
// The formatted string might have a leading newline. If it does, remove it.
|
||||
if (json_line[0] == '\n')
|
||||
{
|
||||
json_line.erase(0, 1);
|
||||
}
|
||||
s_inspector->set_buffer_format(cur_fmt);
|
||||
}
|
||||
}
|
||||
catch (sinsp_exception& e)
|
||||
{
|
||||
sinsp_evt::param_fmt cur_fmt = s_inspector->get_buffer_format();
|
||||
switch(cur_fmt)
|
||||
{
|
||||
case sinsp_evt::PF_NORMAL:
|
||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSON);
|
||||
break;
|
||||
case sinsp_evt::PF_EOLS:
|
||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSONEOLS);
|
||||
break;
|
||||
case sinsp_evt::PF_HEX:
|
||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSONHEX);
|
||||
break;
|
||||
case sinsp_evt::PF_HEXASCII:
|
||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSONHEXASCII);
|
||||
break;
|
||||
case sinsp_evt::PF_BASE64:
|
||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSONBASE64);
|
||||
break;
|
||||
default:
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
// This is output fields
|
||||
s_formatters->tostring((sinsp_evt *)evt, sformat, &json_line);
|
||||
|
||||
// The formatted string might have a leading newline. If it does, remove it.
|
||||
if(json_line[0] == '\n')
|
||||
{
|
||||
json_line.erase(0, 1);
|
||||
}
|
||||
s_inspector->set_buffer_format(cur_fmt);
|
||||
string err = "Invalid output format '" + sformat + "': '" + string(e.what()) + "'";
|
||||
lua_pushstring(ls, err.c_str());
|
||||
lua_error(ls);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
json_event_formatter formatter(s_engine->json_factory(), sformat);
|
||||
try {
|
||||
|
||||
line = formatter.tostring((json_event *)evt);
|
||||
json_event_formatter formatter(s_engine->json_factory(), sformat);
|
||||
|
||||
if(s_json_output)
|
||||
line = formatter.tostring((json_event *) evt);
|
||||
|
||||
if(s_json_output)
|
||||
{
|
||||
json_line = formatter.tojson((json_event *) evt);
|
||||
}
|
||||
}
|
||||
catch (exception &e)
|
||||
{
|
||||
json_line = formatter.tojson((json_event *)evt);
|
||||
string err = "Invalid output format '" + sformat + "': '" + string(e.what()) + "'";
|
||||
lua_pushstring(ls, err.c_str());
|
||||
lua_error(ls);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,16 +217,15 @@ string falco_formats::format_event(const gen_event *evt, const std::string &rule
|
||||
// message as well as the event time in ns. Use this to build
|
||||
// a more detailed object containing the event time, rule,
|
||||
// severity, full output, and fields.
|
||||
if(s_json_output)
|
||||
{
|
||||
if (s_json_output) {
|
||||
Json::Value event;
|
||||
Json::FastWriter writer;
|
||||
string full_line;
|
||||
|
||||
// Convert the time-as-nanoseconds to a more json-friendly ISO8601.
|
||||
time_t evttime = evt->get_ts() / 1000000000;
|
||||
time_t evttime = evt->get_ts()/1000000000;
|
||||
char time_sec[20]; // sizeof "YYYY-MM-DDTHH:MM:SS"
|
||||
char time_ns[12]; // sizeof ".sssssssssZ"
|
||||
char time_ns[12]; // sizeof ".sssssssssZ"
|
||||
string iso8601evttime;
|
||||
|
||||
strftime(time_sec, sizeof(time_sec), "%FT%T", gmtime(&evttime));
|
||||
@@ -201,9 +246,9 @@ string falco_formats::format_event(const gen_event *evt, const std::string &rule
|
||||
|
||||
// Json::FastWriter may add a trailing newline. If it
|
||||
// does, remove it.
|
||||
if(full_line[full_line.length() - 1] == '\n')
|
||||
if (full_line[full_line.length()-1] == '\n')
|
||||
{
|
||||
full_line.resize(full_line.length() - 1);
|
||||
full_line.resize(full_line.length()-1);
|
||||
}
|
||||
|
||||
// Cheat-graft the output from the formatter into this
|
||||
@@ -216,12 +261,24 @@ string falco_formats::format_event(const gen_event *evt, const std::string &rule
|
||||
line = full_line;
|
||||
}
|
||||
|
||||
return line.c_str();
|
||||
lua_pushstring(ls, line.c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
map<string, string> falco_formats::resolve_tokens(const gen_event *evt, const std::string &source, const std::string &format)
|
||||
int falco_formats::resolve_tokens(lua_State *ls)
|
||||
{
|
||||
if(!lua_isstring(ls, -1) ||
|
||||
!lua_isstring(ls, -2) ||
|
||||
!lua_islightuserdata(ls, -3))
|
||||
{
|
||||
lua_pushstring(ls, "Invalid arguments passed to resolve_tokens()");
|
||||
lua_error(ls);
|
||||
}
|
||||
gen_event *evt = (gen_event *)lua_topointer(ls, 1);
|
||||
string source = luaL_checkstring(ls, 2);
|
||||
const char *format = (char *)lua_tostring(ls, 3);
|
||||
string sformat = format;
|
||||
|
||||
map<string, string> values;
|
||||
if(source == "syscall")
|
||||
{
|
||||
@@ -231,7 +288,16 @@ map<string, string> falco_formats::resolve_tokens(const gen_event *evt, const st
|
||||
else
|
||||
{
|
||||
json_event_formatter json_formatter(s_engine->json_factory(), sformat);
|
||||
values = json_formatter.tomap((json_event *)evt);
|
||||
values = json_formatter.tomap((json_event*) evt);
|
||||
}
|
||||
return values;
|
||||
|
||||
lua_newtable(ls);
|
||||
for(auto const& v : values)
|
||||
{
|
||||
lua_pushstring(ls, v.first.c_str());
|
||||
lua_pushstring(ls, v.second.c_str());
|
||||
lua_settable(ls, -3);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
Copyright (C) 2019 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.
|
||||
@@ -18,8 +18,7 @@ limitations under the License.
|
||||
|
||||
#include "sinsp.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
extern "C" {
|
||||
#include "lua.h"
|
||||
#include "lualib.h"
|
||||
#include "lauxlib.h"
|
||||
@@ -32,28 +31,31 @@ class sinsp_evt_formatter;
|
||||
|
||||
class falco_formats
|
||||
{
|
||||
public:
|
||||
static void init(sinsp *inspector,
|
||||
public:
|
||||
static void init(sinsp* inspector,
|
||||
falco_engine *engine,
|
||||
lua_State *ls,
|
||||
bool json_output,
|
||||
bool json_include_output_property);
|
||||
|
||||
// formatter = falco.formatter(format_string)
|
||||
static int lua_formatter(lua_State *ls);
|
||||
static int formatter(lua_State *ls);
|
||||
|
||||
// falco.free_formatter(formatter)
|
||||
static int lua_free_formatter(lua_State *ls);
|
||||
static int free_formatter(lua_State *ls);
|
||||
|
||||
static string format_event(const gen_event *evt, const std::string &rule, const std::string &source,
|
||||
const std::string &level, const std::string &format);
|
||||
// falco.free_formatters()
|
||||
static int free_formatters(lua_State *ls);
|
||||
|
||||
static map<string, string> resolve_tokens(const gen_event *evt, const std::string &source,
|
||||
const std::string &format);
|
||||
// formatted_string = falco.format_event(evt, formatter)
|
||||
static int format_event(lua_State *ls);
|
||||
|
||||
static sinsp *s_inspector;
|
||||
// resolve_tokens = falco.resolve_tokens(evt, formatter)
|
||||
static int resolve_tokens(lua_State *ls);
|
||||
|
||||
static sinsp* s_inspector;
|
||||
static falco_engine *s_engine;
|
||||
static std::unique_ptr<sinsp_evt_formatter_cache> s_formatters;
|
||||
static sinsp_evt_formatter_cache *s_formatters;
|
||||
static bool s_json_output;
|
||||
static bool s_json_include_output_property;
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
-- Copyright (C) 2019 The Falco Authors.
|
||||
-- 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.
|
||||
@@ -11,25 +11,24 @@
|
||||
-- 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.
|
||||
|
||||
local parser = require("parser")
|
||||
local compiler = {}
|
||||
|
||||
compiler.trim = parser.trim
|
||||
|
||||
function map(f, arr)
|
||||
local res = {}
|
||||
for i,v in ipairs(arr) do
|
||||
res[i] = f(v)
|
||||
end
|
||||
return res
|
||||
local res = {}
|
||||
for i, v in ipairs(arr) do
|
||||
res[i] = f(v)
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
function foldr(f, acc, arr)
|
||||
for i,v in pairs(arr) do
|
||||
acc = f(acc, v)
|
||||
end
|
||||
return acc
|
||||
for i, v in pairs(arr) do
|
||||
acc = f(acc, v)
|
||||
end
|
||||
return acc
|
||||
end
|
||||
|
||||
--[[
|
||||
@@ -47,181 +46,192 @@ end
|
||||
--]]
|
||||
|
||||
function copy_ast_obj(obj)
|
||||
if type(obj) ~= 'table' then return obj end
|
||||
local res = {}
|
||||
for k, v in pairs(obj) do res[copy_ast_obj(k)] = copy_ast_obj(v) end
|
||||
return res
|
||||
if type(obj) ~= 'table' then
|
||||
return obj
|
||||
end
|
||||
local res = {}
|
||||
for k, v in pairs(obj) do
|
||||
res[copy_ast_obj(k)] = copy_ast_obj(v)
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
function expand_macros(ast, defs, changed)
|
||||
|
||||
if (ast.type == "Rule") then
|
||||
return expand_macros(ast.filter, defs, changed)
|
||||
elseif ast.type == "Filter" then
|
||||
if (ast.value.type == "Macro") then
|
||||
if (defs[ast.value.value] == nil) then
|
||||
return false, "Undefined macro '".. ast.value.value .. "' used in filter."
|
||||
end
|
||||
defs[ast.value.value].used = true
|
||||
ast.value = copy_ast_obj(defs[ast.value.value].ast)
|
||||
changed = true
|
||||
return true, changed
|
||||
end
|
||||
return expand_macros(ast.value, defs, changed)
|
||||
if (ast.type == "Rule") then
|
||||
return expand_macros(ast.filter, defs, changed)
|
||||
elseif ast.type == "Filter" then
|
||||
if (ast.value.type == "Macro") then
|
||||
if (defs[ast.value.value] == nil) then
|
||||
return false, "Undefined macro '" .. ast.value.value .. "' used in filter."
|
||||
end
|
||||
defs[ast.value.value].used = true
|
||||
ast.value = copy_ast_obj(defs[ast.value.value].ast)
|
||||
changed = true
|
||||
return true, changed
|
||||
end
|
||||
return expand_macros(ast.value, defs, changed)
|
||||
|
||||
elseif ast.type == "BinaryBoolOp" then
|
||||
elseif ast.type == "BinaryBoolOp" then
|
||||
|
||||
if (ast.left.type == "Macro") then
|
||||
if (defs[ast.left.value] == nil) then
|
||||
return false, "Undefined macro '".. ast.left.value .. "' used in filter."
|
||||
end
|
||||
defs[ast.left.value].used = true
|
||||
ast.left = copy_ast_obj(defs[ast.left.value].ast)
|
||||
changed = true
|
||||
end
|
||||
if (ast.left.type == "Macro") then
|
||||
if (defs[ast.left.value] == nil) then
|
||||
return false, "Undefined macro '" .. ast.left.value .. "' used in filter."
|
||||
end
|
||||
defs[ast.left.value].used = true
|
||||
ast.left = copy_ast_obj(defs[ast.left.value].ast)
|
||||
changed = true
|
||||
end
|
||||
|
||||
if (ast.right.type == "Macro") then
|
||||
if (defs[ast.right.value] == nil) then
|
||||
return false, "Undefined macro ".. ast.right.value .. " used in filter."
|
||||
end
|
||||
defs[ast.right.value].used = true
|
||||
ast.right = copy_ast_obj(defs[ast.right.value].ast)
|
||||
changed = true
|
||||
end
|
||||
if (ast.right.type == "Macro") then
|
||||
if (defs[ast.right.value] == nil) then
|
||||
return false, "Undefined macro " .. ast.right.value .. " used in filter."
|
||||
end
|
||||
defs[ast.right.value].used = true
|
||||
ast.right = copy_ast_obj(defs[ast.right.value].ast)
|
||||
changed = true
|
||||
end
|
||||
|
||||
local status, changed_left = expand_macros(ast.left, defs, false)
|
||||
if status == false then
|
||||
return false, changed_left
|
||||
end
|
||||
local status, changed_right = expand_macros(ast.right, defs, false)
|
||||
if status == false then
|
||||
return false, changed_right
|
||||
end
|
||||
return true, changed or changed_left or changed_right
|
||||
local status, changed_left = expand_macros(ast.left, defs, false)
|
||||
if status == false then
|
||||
return false, changed_left
|
||||
end
|
||||
local status, changed_right = expand_macros(ast.right, defs, false)
|
||||
if status == false then
|
||||
return false, changed_right
|
||||
end
|
||||
return true, changed or changed_left or changed_right
|
||||
|
||||
elseif ast.type == "UnaryBoolOp" then
|
||||
if (ast.argument.type == "Macro") then
|
||||
if (defs[ast.argument.value] == nil) then
|
||||
return false, "Undefined macro ".. ast.argument.value .. " used in filter."
|
||||
end
|
||||
defs[ast.argument.value].used = true
|
||||
ast.argument = copy_ast_obj(defs[ast.argument.value].ast)
|
||||
changed = true
|
||||
end
|
||||
return expand_macros(ast.argument, defs, changed)
|
||||
end
|
||||
return true, changed
|
||||
elseif ast.type == "UnaryBoolOp" then
|
||||
if (ast.argument.type == "Macro") then
|
||||
if (defs[ast.argument.value] == nil) then
|
||||
return false, "Undefined macro " .. ast.argument.value .. " used in filter."
|
||||
end
|
||||
defs[ast.argument.value].used = true
|
||||
ast.argument = copy_ast_obj(defs[ast.argument.value].ast)
|
||||
changed = true
|
||||
end
|
||||
return expand_macros(ast.argument, defs, changed)
|
||||
end
|
||||
return true, changed
|
||||
end
|
||||
|
||||
function get_macros(ast, set)
|
||||
if (ast.type == "Macro") then
|
||||
set[ast.value] = true
|
||||
return set
|
||||
end
|
||||
if (ast.type == "Macro") then
|
||||
set[ast.value] = true
|
||||
return set
|
||||
end
|
||||
|
||||
if ast.type == "Filter" then
|
||||
return get_macros(ast.value, set)
|
||||
end
|
||||
if ast.type == "Filter" then
|
||||
return get_macros(ast.value, set)
|
||||
end
|
||||
|
||||
if ast.type == "BinaryBoolOp" then
|
||||
local left = get_macros(ast.left, {})
|
||||
local right = get_macros(ast.right, {})
|
||||
if ast.type == "BinaryBoolOp" then
|
||||
local left = get_macros(ast.left, {})
|
||||
local right = get_macros(ast.right, {})
|
||||
|
||||
for m, _ in pairs(left) do set[m] = true end
|
||||
for m, _ in pairs(right) do set[m] = true end
|
||||
for m, _ in pairs(left) do
|
||||
set[m] = true
|
||||
end
|
||||
for m, _ in pairs(right) do
|
||||
set[m] = true
|
||||
end
|
||||
|
||||
return set
|
||||
end
|
||||
if ast.type == "UnaryBoolOp" then
|
||||
return get_macros(ast.argument, set)
|
||||
end
|
||||
return set
|
||||
return set
|
||||
end
|
||||
if ast.type == "UnaryBoolOp" then
|
||||
return get_macros(ast.argument, set)
|
||||
end
|
||||
return set
|
||||
end
|
||||
|
||||
function get_filters(ast)
|
||||
|
||||
local filters = {}
|
||||
local filters = {}
|
||||
|
||||
function cb(node)
|
||||
if node.type == "FieldName" then
|
||||
filters[node.value] = 1
|
||||
end
|
||||
end
|
||||
function cb(node)
|
||||
if node.type == "FieldName" then
|
||||
filters[node.value] = 1
|
||||
end
|
||||
end
|
||||
|
||||
parser.traverse_ast(ast.filter.value, {FieldName=1} , cb)
|
||||
parser.traverse_ast(ast.filter.value, {
|
||||
FieldName = 1
|
||||
}, cb)
|
||||
|
||||
return filters
|
||||
return filters
|
||||
end
|
||||
|
||||
function compiler.expand_lists_in(source, list_defs)
|
||||
|
||||
for name, def in pairs(list_defs) do
|
||||
for name, def in pairs(list_defs) do
|
||||
|
||||
local bpos = string.find(source, name, 1, true)
|
||||
local bpos = string.find(source, name, 1, true)
|
||||
|
||||
while bpos ~= nil do
|
||||
def.used = true
|
||||
while bpos ~= nil do
|
||||
def.used = true
|
||||
|
||||
local epos = bpos + string.len(name)
|
||||
local epos = bpos + string.len(name)
|
||||
|
||||
-- The characters surrounding the name must be delimiters of beginning/end of string
|
||||
if (bpos == 1 or string.match(string.sub(source, bpos-1, bpos-1), "[%s(),=]")) and (epos > string.len(source) or string.match(string.sub(source, epos, epos), "[%s(),=]")) then
|
||||
new_source = ""
|
||||
-- The characters surrounding the name must be delimiters of beginning/end of string
|
||||
if (bpos == 1 or string.match(string.sub(source, bpos - 1, bpos - 1), "[%s(),=]")) and
|
||||
(epos > string.len(source) or string.match(string.sub(source, epos, epos), "[%s(),=]")) then
|
||||
new_source = ""
|
||||
|
||||
if bpos > 1 then
|
||||
new_source = new_source..string.sub(source, 1, bpos-1)
|
||||
end
|
||||
if bpos > 1 then
|
||||
new_source = new_source .. string.sub(source, 1, bpos - 1)
|
||||
end
|
||||
|
||||
sub = table.concat(def.items, ", ")
|
||||
sub = table.concat(def.items, ", ")
|
||||
|
||||
new_source = new_source..sub
|
||||
new_source = new_source .. sub
|
||||
|
||||
if epos <= string.len(source) then
|
||||
new_source = new_source..string.sub(source, epos, string.len(source))
|
||||
end
|
||||
if epos <= string.len(source) then
|
||||
new_source = new_source .. string.sub(source, epos, string.len(source))
|
||||
end
|
||||
|
||||
source = new_source
|
||||
bpos = bpos + (string.len(sub)-string.len(name))
|
||||
end
|
||||
source = new_source
|
||||
bpos = bpos + (string.len(sub) - string.len(name))
|
||||
end
|
||||
|
||||
bpos = string.find(source, name, bpos+1, true)
|
||||
end
|
||||
end
|
||||
bpos = string.find(source, name, bpos + 1, true)
|
||||
end
|
||||
end
|
||||
|
||||
return source
|
||||
return source
|
||||
end
|
||||
|
||||
function compiler.compile_macro(line, macro_defs, list_defs)
|
||||
|
||||
line = compiler.expand_lists_in(line, list_defs)
|
||||
line = compiler.expand_lists_in(line, list_defs)
|
||||
|
||||
local ast, error_msg = parser.parse_filter(line)
|
||||
local ast, error_msg = parser.parse_filter(line)
|
||||
|
||||
if (error_msg) then
|
||||
msg = "Compilation error when compiling \""..line.."\": ".. error_msg
|
||||
return false, msg
|
||||
end
|
||||
if (error_msg) then
|
||||
msg = "Compilation error when compiling \"" .. line .. "\": " .. error_msg
|
||||
return false, msg
|
||||
end
|
||||
|
||||
-- Simply as a validation step, try to expand all macros in this
|
||||
-- macro's condition. This changes the ast, so we make a copy
|
||||
-- first.
|
||||
local ast_copy = copy_ast_obj(ast)
|
||||
-- Simply as a validation step, try to expand all macros in this
|
||||
-- macro's condition. This changes the ast, so we make a copy
|
||||
-- first.
|
||||
local ast_copy = copy_ast_obj(ast)
|
||||
|
||||
if (ast.type == "Rule") then
|
||||
-- Line is a filter, so expand macro references
|
||||
repeat
|
||||
status, expanded = expand_macros(ast_copy, macro_defs, false)
|
||||
if status == false then
|
||||
msg = "Compilation error when compiling \""..line.."\": ".. expanded
|
||||
return false, msg
|
||||
end
|
||||
until expanded == false
|
||||
if (ast.type == "Rule") then
|
||||
-- Line is a filter, so expand macro references
|
||||
repeat
|
||||
status, expanded = expand_macros(ast_copy, macro_defs, false)
|
||||
if status == false then
|
||||
msg = "Compilation error when compiling \"" .. line .. "\": " .. expanded
|
||||
return false, msg
|
||||
end
|
||||
until expanded == false
|
||||
|
||||
else
|
||||
return false, "Unexpected top-level AST type: "..ast.type
|
||||
end
|
||||
else
|
||||
return false, "Unexpected top-level AST type: " .. ast.type
|
||||
end
|
||||
|
||||
return true, ast
|
||||
return true, ast
|
||||
end
|
||||
|
||||
--[[
|
||||
@@ -229,32 +239,31 @@ end
|
||||
--]]
|
||||
function compiler.compile_filter(name, source, macro_defs, list_defs)
|
||||
|
||||
source = compiler.expand_lists_in(source, list_defs)
|
||||
source = compiler.expand_lists_in(source, list_defs)
|
||||
|
||||
local ast, error_msg = parser.parse_filter(source)
|
||||
local ast, error_msg = parser.parse_filter(source)
|
||||
|
||||
if (error_msg) then
|
||||
msg = "Compilation error when compiling \""..source.."\": "..error_msg
|
||||
return false, msg
|
||||
end
|
||||
if (error_msg) then
|
||||
msg = "Compilation error when compiling \"" .. source .. "\": " .. error_msg
|
||||
return false, msg
|
||||
end
|
||||
|
||||
if (ast.type == "Rule") then
|
||||
-- Line is a filter, so expand macro references
|
||||
repeat
|
||||
status, expanded = expand_macros(ast, macro_defs, false)
|
||||
if status == false then
|
||||
return false, expanded
|
||||
end
|
||||
until expanded == false
|
||||
if (ast.type == "Rule") then
|
||||
-- Line is a filter, so expand macro references
|
||||
repeat
|
||||
status, expanded = expand_macros(ast, macro_defs, false)
|
||||
if status == false then
|
||||
return false, expanded
|
||||
end
|
||||
until expanded == false
|
||||
|
||||
else
|
||||
return false, "Unexpected top-level AST type: "..ast.type
|
||||
end
|
||||
else
|
||||
return false, "Unexpected top-level AST type: " .. ast.type
|
||||
end
|
||||
|
||||
filters = get_filters(ast)
|
||||
filters = get_filters(ast)
|
||||
|
||||
return true, ast, filters
|
||||
return true, ast, filters
|
||||
end
|
||||
|
||||
|
||||
return compiler
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
-- Copyright (C) 2019 The Falco Authors.
|
||||
-- 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.
|
||||
@@ -12,7 +12,6 @@
|
||||
-- See the License for the specific language governing permissions and
|
||||
-- limitations under the License.
|
||||
--
|
||||
|
||||
--[[
|
||||
Falco grammar and parser.
|
||||
|
||||
@@ -40,232 +39,258 @@ local space = lpeg.space
|
||||
|
||||
-- creates an error message for the input string
|
||||
local function syntaxerror(errorinfo, pos, msg)
|
||||
local error_msg = "%s: syntax error, %s"
|
||||
return string.format(error_msg, pos, msg)
|
||||
local error_msg = "%s: syntax error, %s"
|
||||
return string.format(error_msg, pos, msg)
|
||||
end
|
||||
|
||||
-- gets the farthest failure position
|
||||
local function getffp(s, i, t)
|
||||
return t.ffp or i, t
|
||||
return t.ffp or i, t
|
||||
end
|
||||
|
||||
-- gets the table that contains the error information
|
||||
local function geterrorinfo()
|
||||
return Cmt(Carg(1), getffp) * (C(V "OneWord") + Cc("EOF")) / function(t, u)
|
||||
t.unexpected = u
|
||||
return t
|
||||
end
|
||||
return Cmt(Carg(1), getffp) * (C(V "OneWord") + Cc("EOF")) / function(t, u)
|
||||
t.unexpected = u
|
||||
return t
|
||||
end
|
||||
end
|
||||
|
||||
-- creates an errror message using the farthest failure position
|
||||
local function errormsg()
|
||||
return geterrorinfo() / function(t)
|
||||
local p = t.ffp or 1
|
||||
local msg = "unexpected '%s', expecting %s"
|
||||
msg = string.format(msg, t.unexpected, t.expected)
|
||||
return nil, syntaxerror(t, p, msg)
|
||||
end
|
||||
return geterrorinfo() / function(t)
|
||||
local p = t.ffp or 1
|
||||
local msg = "unexpected '%s', expecting %s"
|
||||
msg = string.format(msg, t.unexpected, t.expected)
|
||||
return nil, syntaxerror(t, p, msg)
|
||||
end
|
||||
end
|
||||
|
||||
-- reports a syntactic error
|
||||
local function report_error()
|
||||
return errormsg()
|
||||
return errormsg()
|
||||
end
|
||||
|
||||
--- sets the farthest failure position and the expected tokens
|
||||
local function setffp(s, i, t, n)
|
||||
if not t.ffp or i > t.ffp then
|
||||
t.ffp = i
|
||||
t.list = {}
|
||||
t.list[n] = n
|
||||
t.expected = "'" .. n .. "'"
|
||||
elseif i == t.ffp then
|
||||
if not t.list[n] then
|
||||
t.list[n] = n
|
||||
t.expected = "'" .. n .. "', " .. t.expected
|
||||
end
|
||||
end
|
||||
return false
|
||||
if not t.ffp or i > t.ffp then
|
||||
t.ffp = i
|
||||
t.list = {}
|
||||
t.list[n] = n
|
||||
t.expected = "'" .. n .. "'"
|
||||
elseif i == t.ffp then
|
||||
if not t.list[n] then
|
||||
t.list[n] = n
|
||||
t.expected = "'" .. n .. "', " .. t.expected
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function updateffp(name)
|
||||
return Cmt(Carg(1) * Cc(name), setffp)
|
||||
return Cmt(Carg(1) * Cc(name), setffp)
|
||||
end
|
||||
|
||||
-- regular combinators and auxiliary functions
|
||||
|
||||
local function token(pat, name)
|
||||
return pat * V "Skip" + updateffp(name) * P(false)
|
||||
return pat * V "Skip" + updateffp(name) * P(false)
|
||||
end
|
||||
|
||||
local function symb(str)
|
||||
return token(P(str), str)
|
||||
return token(P(str), str)
|
||||
end
|
||||
|
||||
local function kw(str)
|
||||
return token(P(str) * -V "idRest", str)
|
||||
return token(P(str) * -V "idRest", str)
|
||||
end
|
||||
|
||||
local function list(pat, sep)
|
||||
return Ct(pat ^ -1 * (sep * pat ^ 0) ^ 0) / function(elements)
|
||||
return {type = "List", elements = elements}
|
||||
end
|
||||
return Ct(pat ^ -1 * (sep * pat ^ 0) ^ 0) / function(elements)
|
||||
return {
|
||||
type = "List",
|
||||
elements = elements
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
--http://lua-users.org/wiki/StringTrim
|
||||
-- http://lua-users.org/wiki/StringTrim
|
||||
function trim(s)
|
||||
if (type(s) ~= "string") then
|
||||
return s
|
||||
end
|
||||
return (s:gsub("^%s*(.-)%s*$", "%1"))
|
||||
if (type(s) ~= "string") then
|
||||
return s
|
||||
end
|
||||
return (s:gsub("^%s*(.-)%s*$", "%1"))
|
||||
end
|
||||
parser.trim = trim
|
||||
|
||||
local function terminal(tag)
|
||||
-- Rather than trim the whitespace in this way, it would be nicer to exclude it from the capture...
|
||||
return token(V(tag), tag) / function(tok)
|
||||
val = tok
|
||||
if tag ~= "String" then
|
||||
-- Rather than trim the whitespace in this way, it would be nicer to exclude it from the capture...
|
||||
return token(V(tag), tag) / function(tok)
|
||||
val = tok
|
||||
if tag ~= "String" then
|
||||
val = trim(tok)
|
||||
end
|
||||
return {type = tag, value = val}
|
||||
end
|
||||
end
|
||||
return {
|
||||
type = tag,
|
||||
value = val
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
local function unaryboolop(op, e)
|
||||
return {type = "UnaryBoolOp", operator = op, argument = e}
|
||||
return {
|
||||
type = "UnaryBoolOp",
|
||||
operator = op,
|
||||
argument = e
|
||||
}
|
||||
end
|
||||
|
||||
local function unaryrelop(e, op)
|
||||
return {type = "UnaryRelOp", operator = op, argument = e}
|
||||
return {
|
||||
type = "UnaryRelOp",
|
||||
operator = op,
|
||||
argument = e
|
||||
}
|
||||
end
|
||||
|
||||
local function binaryop(e1, op, e2)
|
||||
if not op then
|
||||
return e1
|
||||
else
|
||||
return {type = "BinaryBoolOp", operator = op, left = e1, right = e2}
|
||||
end
|
||||
if not op then
|
||||
return e1
|
||||
else
|
||||
return {
|
||||
type = "BinaryBoolOp",
|
||||
operator = op,
|
||||
left = e1,
|
||||
right = e2
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
local function bool(pat, sep)
|
||||
return Cf(pat * Cg(sep * pat) ^ 0, binaryop)
|
||||
return Cf(pat * Cg(sep * pat) ^ 0, binaryop)
|
||||
end
|
||||
|
||||
local function rel(left, sep, right)
|
||||
return left * sep * right / function(e1, op, e2)
|
||||
return {type = "BinaryRelOp", operator = op, left = e1, right = e2}
|
||||
end
|
||||
return left * sep * right / function(e1, op, e2)
|
||||
return {
|
||||
type = "BinaryRelOp",
|
||||
operator = op,
|
||||
left = e1,
|
||||
right = e2
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
-- grammar
|
||||
|
||||
local function filter(e)
|
||||
return {type = "Filter", value = e}
|
||||
return {
|
||||
type = "Filter",
|
||||
value = e
|
||||
}
|
||||
end
|
||||
|
||||
local function rule(filter)
|
||||
return {type = "Rule", filter = filter}
|
||||
return {
|
||||
type = "Rule",
|
||||
filter = filter
|
||||
}
|
||||
end
|
||||
|
||||
local G = {
|
||||
V "Start", -- Entry rule
|
||||
Start = V "Skip" * (V "Comment" + V "Rule" / rule) ^ -1 * -1 + report_error(),
|
||||
-- Grammar
|
||||
Comment = P "#" * P(1) ^ 0,
|
||||
Rule = V "Filter" / filter * ((V "Skip") ^ -1),
|
||||
Filter = V "OrExpression",
|
||||
OrExpression = bool(V "AndExpression", V "OrOp"),
|
||||
AndExpression = bool(V "NotExpression", V "AndOp"),
|
||||
NotExpression = V "UnaryBoolOp" * V "NotExpression" / unaryboolop + V "ExistsExpression",
|
||||
ExistsExpression = terminal "FieldName" * V "ExistsOp" / unaryrelop + V "MacroExpression",
|
||||
MacroExpression = terminal "Macro" + V "RelationalExpression",
|
||||
RelationalExpression = rel(terminal "FieldName", V "RelOp", V "Value") +
|
||||
rel(terminal "FieldName", V "SetOp", V "InList") +
|
||||
V "PrimaryExp",
|
||||
PrimaryExp = symb("(") * V "Filter" * symb(")"),
|
||||
FuncArgs = symb("(") * list(V "Value", symb(",")) * symb(")"),
|
||||
-- Terminals
|
||||
Value = terminal "Number" + terminal "String" + terminal "BareString",
|
||||
InList = symb("(") * list(V "Value", symb(",")) * symb(")"),
|
||||
-- Lexemes
|
||||
Space = space ^ 1,
|
||||
Skip = (V "Space") ^ 0,
|
||||
idStart = alpha + P("_"),
|
||||
idRest = alnum + P("_"),
|
||||
Identifier = V "idStart" * V "idRest" ^ 0,
|
||||
Macro = V "idStart" * V "idRest" ^ 0 * -P ".",
|
||||
Int = digit ^ 1,
|
||||
PathString = (alnum + S ",.-_/*?") ^ 1,
|
||||
PortRangeString = (V "Int" + S ":,") ^ 1,
|
||||
Index = V "PortRangeString" + V "Int" + V "PathString",
|
||||
FieldName = V "Identifier" * (P "." + V "Identifier") ^ 1 * (P "[" * V "Index" * P "]") ^ -1,
|
||||
Name = C(V "Identifier") * -V "idRest",
|
||||
Hex = (P("0x") + P("0X")) * xdigit ^ 1,
|
||||
Expo = S("eE") * S("+-") ^ -1 * digit ^ 1,
|
||||
Float = (((digit ^ 1 * P(".") * digit ^ 0) + (P(".") * digit ^ 1)) * V "Expo" ^ -1) + (digit ^ 1 * V "Expo"),
|
||||
Number = C(V "Hex" + V "Float" + V "Int") / function(n)
|
||||
return tonumber(n)
|
||||
end,
|
||||
String = (P '"' * C(((P "\\" * P(1)) + (P(1) - P '"')) ^ 0) * P '"' +
|
||||
P "'" * C(((P "\\" * P(1)) + (P(1) - P "'")) ^ 0) * P "'"),
|
||||
BareString = C((P(1) - S " (),=") ^ 1),
|
||||
OrOp = kw("or") / "or",
|
||||
AndOp = kw("and") / "and",
|
||||
Colon = kw(":"),
|
||||
RelOp = symb("=") / "=" + symb("==") / "==" + symb("!=") / "!=" + symb("<=") / "<=" + symb(">=") / ">=" +
|
||||
symb("<") / "<" +
|
||||
symb(">") / ">" +
|
||||
symb("contains") / "contains" +
|
||||
symb("icontains") / "icontains" +
|
||||
symb("glob") / "glob" +
|
||||
symb("startswith") / "startswith" +
|
||||
symb("endswith") / "endswith",
|
||||
SetOp = kw("in") / "in" + kw("intersects") / "intersects" + kw("pmatch") / "pmatch",
|
||||
UnaryBoolOp = kw("not") / "not",
|
||||
ExistsOp = kw("exists") / "exists",
|
||||
-- for error reporting
|
||||
OneWord = V "Name" + V "Number" + V "String" + P(1)
|
||||
V "Start", -- Entry rule
|
||||
Start = V "Skip" * (V "Comment" + V "Rule" / rule) ^ -1 * -1 + report_error(),
|
||||
-- Grammar
|
||||
Comment = P "#" * P(1) ^ 0,
|
||||
Rule = V "Filter" / filter * ((V "Skip") ^ -1),
|
||||
Filter = V "OrExpression",
|
||||
OrExpression = bool(V "AndExpression", V "OrOp"),
|
||||
AndExpression = bool(V "NotExpression", V "AndOp"),
|
||||
NotExpression = V "UnaryBoolOp" * V "NotExpression" / unaryboolop + V "ExistsExpression",
|
||||
ExistsExpression = terminal "FieldName" * V "ExistsOp" / unaryrelop + V "MacroExpression",
|
||||
MacroExpression = terminal "Macro" + V "RelationalExpression",
|
||||
RelationalExpression = rel(terminal "FieldName", V "RelOp", V "Value") +
|
||||
rel(terminal "FieldName", V "SetOp", V "InList") + V "PrimaryExp",
|
||||
PrimaryExp = symb("(") * V "Filter" * symb(")"),
|
||||
FuncArgs = symb("(") * list(V "Value", symb(",")) * symb(")"),
|
||||
-- Terminals
|
||||
Value = terminal "Number" + terminal "String" + terminal "BareString",
|
||||
InList = symb("(") * list(V "Value", symb(",")) * symb(")"),
|
||||
-- Lexemes
|
||||
Space = space ^ 1,
|
||||
Skip = (V "Space") ^ 0,
|
||||
idStart = alpha + P("_"),
|
||||
idRest = alnum + P("_"),
|
||||
Identifier = V "idStart" * V "idRest" ^ 0,
|
||||
Macro = V "idStart" * V "idRest" ^ 0 * -P ".",
|
||||
Int = digit ^ 1,
|
||||
PathString = (alnum + S ",.-_/*?") ^ 1,
|
||||
PortRangeString = (V "Int" + S ":,") ^ 1,
|
||||
Index = V "PortRangeString" + V "Int" + V "PathString",
|
||||
FieldName = V "Identifier" * (P "." + V "Identifier") ^ 1 * (P "[" * V "Index" * P "]") ^ -1,
|
||||
Name = C(V "Identifier") * -V "idRest",
|
||||
Hex = (P("0x") + P("0X")) * xdigit ^ 1,
|
||||
Expo = S("eE") * S("+-") ^ -1 * digit ^ 1,
|
||||
Float = (((digit ^ 1 * P(".") * digit ^ 0) + (P(".") * digit ^ 1)) * V "Expo" ^ -1) + (digit ^ 1 * V "Expo"),
|
||||
Number = C(V "Hex" + V "Float" + V "Int") / function(n)
|
||||
return tonumber(n)
|
||||
end,
|
||||
String = (P '"' * C(((P "\\" * P(1)) + (P(1) - P '"')) ^ 0) * P '"' + P "'" *
|
||||
C(((P "\\" * P(1)) + (P(1) - P "'")) ^ 0) * P "'"),
|
||||
BareString = C((P(1) - S " (),=") ^ 1),
|
||||
OrOp = kw("or") / "or",
|
||||
AndOp = kw("and") / "and",
|
||||
Colon = kw(":"),
|
||||
RelOp = symb("=") / "=" + symb("==") / "==" + symb("!=") / "!=" + symb("<=") / "<=" + symb(">=") / ">=" + symb("<") /
|
||||
"<" + symb(">") / ">" + symb("contains") / "contains" + symb("icontains") / "icontains" + symb("glob") / "glob" +
|
||||
symb("startswith") / "startswith" + symb("endswith") / "endswith",
|
||||
SetOp = kw("in") / "in" + kw("intersects") / "intersects" + kw("pmatch") / "pmatch",
|
||||
UnaryBoolOp = kw("not") / "not",
|
||||
ExistsOp = kw("exists") / "exists",
|
||||
-- for error reporting
|
||||
OneWord = V "Name" + V "Number" + V "String" + P(1)
|
||||
}
|
||||
|
||||
--[[
|
||||
Parses a single filter and returns the AST.
|
||||
--]]
|
||||
function parser.parse_filter(subject)
|
||||
local errorinfo = {subject = subject}
|
||||
lpeg.setmaxstack(1000)
|
||||
local ast, error_msg = lpeg.match(G, subject, nil, errorinfo)
|
||||
return ast, error_msg
|
||||
local errorinfo = {
|
||||
subject = subject
|
||||
}
|
||||
lpeg.setmaxstack(1000)
|
||||
local ast, error_msg = lpeg.match(G, subject, nil, errorinfo)
|
||||
return ast, error_msg
|
||||
end
|
||||
|
||||
function print_ast(ast, level)
|
||||
local t = ast.type
|
||||
level = level or 0
|
||||
local prefix = string.rep(" ", level * 4)
|
||||
level = level + 1
|
||||
local t = ast.type
|
||||
level = level or 0
|
||||
local prefix = string.rep(" ", level * 4)
|
||||
level = level + 1
|
||||
|
||||
if t == "Rule" then
|
||||
print_ast(ast.filter, level)
|
||||
elseif t == "Filter" then
|
||||
print_ast(ast.value, level)
|
||||
elseif t == "BinaryBoolOp" or t == "BinaryRelOp" then
|
||||
print(prefix .. ast.operator)
|
||||
print_ast(ast.left, level)
|
||||
print_ast(ast.right, level)
|
||||
elseif t == "UnaryRelOp" or t == "UnaryBoolOp" then
|
||||
print(prefix .. ast.operator)
|
||||
print_ast(ast.argument, level)
|
||||
elseif t == "List" then
|
||||
for i, v in ipairs(ast.elements) do
|
||||
print_ast(v, level)
|
||||
end
|
||||
elseif t == "FieldName" or t == "Number" or t == "String" or t == "BareString" or t == "Macro" then
|
||||
print(prefix .. t .. " " .. ast.value)
|
||||
elseif t == "MacroDef" then
|
||||
-- don't print for now
|
||||
else
|
||||
error("Unexpected type in print_ast: " .. t)
|
||||
end
|
||||
if t == "Rule" then
|
||||
print_ast(ast.filter, level)
|
||||
elseif t == "Filter" then
|
||||
print_ast(ast.value, level)
|
||||
elseif t == "BinaryBoolOp" or t == "BinaryRelOp" then
|
||||
print(prefix .. ast.operator)
|
||||
print_ast(ast.left, level)
|
||||
print_ast(ast.right, level)
|
||||
elseif t == "UnaryRelOp" or t == "UnaryBoolOp" then
|
||||
print(prefix .. ast.operator)
|
||||
print_ast(ast.argument, level)
|
||||
elseif t == "List" then
|
||||
for i, v in ipairs(ast.elements) do
|
||||
print_ast(v, level)
|
||||
end
|
||||
elseif t == "FieldName" or t == "Number" or t == "String" or t == "BareString" or t == "Macro" then
|
||||
print(prefix .. t .. " " .. ast.value)
|
||||
elseif t == "MacroDef" then
|
||||
-- don't print for now
|
||||
else
|
||||
error("Unexpected type in print_ast: " .. t)
|
||||
end
|
||||
end
|
||||
parser.print_ast = print_ast
|
||||
|
||||
@@ -275,32 +300,32 @@ parser.print_ast = print_ast
|
||||
-- cb(ast_node, ctx)
|
||||
-- ctx is optional.
|
||||
function traverse_ast(ast, node_types, cb, ctx)
|
||||
local t = ast.type
|
||||
local t = ast.type
|
||||
|
||||
if node_types[t] ~= nil then
|
||||
cb(ast, ctx)
|
||||
end
|
||||
if node_types[t] ~= nil then
|
||||
cb(ast, ctx)
|
||||
end
|
||||
|
||||
if t == "Rule" then
|
||||
traverse_ast(ast.filter, node_types, cb, ctx)
|
||||
elseif t == "Filter" then
|
||||
traverse_ast(ast.value, node_types, cb, ctx)
|
||||
elseif t == "BinaryBoolOp" or t == "BinaryRelOp" then
|
||||
traverse_ast(ast.left, node_types, cb, ctx)
|
||||
traverse_ast(ast.right, node_types, cb, ctx)
|
||||
elseif t == "UnaryRelOp" or t == "UnaryBoolOp" then
|
||||
traverse_ast(ast.argument, node_types, cb, ctx)
|
||||
elseif t == "List" then
|
||||
for i, v in ipairs(ast.elements) do
|
||||
traverse_ast(v, node_types, cb, ctx)
|
||||
end
|
||||
elseif t == "MacroDef" then
|
||||
traverse_ast(ast.value, node_types, cb, ctx)
|
||||
elseif t == "FieldName" or t == "Number" or t == "String" or t == "BareString" or t == "Macro" then
|
||||
-- do nothing, no traversal needed
|
||||
else
|
||||
error("Unexpected type in traverse_ast: " .. t)
|
||||
end
|
||||
if t == "Rule" then
|
||||
traverse_ast(ast.filter, node_types, cb, ctx)
|
||||
elseif t == "Filter" then
|
||||
traverse_ast(ast.value, node_types, cb, ctx)
|
||||
elseif t == "BinaryBoolOp" or t == "BinaryRelOp" then
|
||||
traverse_ast(ast.left, node_types, cb, ctx)
|
||||
traverse_ast(ast.right, node_types, cb, ctx)
|
||||
elseif t == "UnaryRelOp" or t == "UnaryBoolOp" then
|
||||
traverse_ast(ast.argument, node_types, cb, ctx)
|
||||
elseif t == "List" then
|
||||
for i, v in ipairs(ast.elements) do
|
||||
traverse_ast(v, node_types, cb, ctx)
|
||||
end
|
||||
elseif t == "MacroDef" then
|
||||
traverse_ast(ast.value, node_types, cb, ctx)
|
||||
elseif t == "FieldName" or t == "Number" or t == "String" or t == "BareString" or t == "Macro" then
|
||||
-- do nothing, no traversal needed
|
||||
else
|
||||
error("Unexpected type in traverse_ast: " .. t)
|
||||
end
|
||||
end
|
||||
parser.traverse_ast = traverse_ast
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
-- Copyright (C) 2019 The Falco Authors.
|
||||
-- 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.
|
||||
@@ -12,55 +12,52 @@
|
||||
-- See the License for the specific language governing permissions and
|
||||
-- limitations under the License.
|
||||
--
|
||||
|
||||
local parser = require("parser")
|
||||
local sinsp_rule_utils = {}
|
||||
|
||||
function sinsp_rule_utils.check_for_ignored_syscalls_events(ast, filter_type, source)
|
||||
|
||||
function check_syscall(val)
|
||||
if ignored_syscalls[val] then
|
||||
error("Ignored syscall \""..val.."\" in "..filter_type..": "..source)
|
||||
end
|
||||
function check_syscall(val)
|
||||
if ignored_syscalls[val] then
|
||||
error("Ignored syscall \"" .. val .. "\" in " .. filter_type .. ": " .. source)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function check_event(val)
|
||||
if ignored_events[val] then
|
||||
error("Ignored event \""..val.."\" in "..filter_type..": "..source)
|
||||
end
|
||||
end
|
||||
function check_event(val)
|
||||
if ignored_events[val] then
|
||||
error("Ignored event \"" .. val .. "\" in " .. filter_type .. ": " .. source)
|
||||
end
|
||||
end
|
||||
|
||||
function cb(node)
|
||||
if node.left.type == "FieldName" and
|
||||
(node.left.value == "evt.type" or
|
||||
node.left.value == "syscall.type") then
|
||||
function cb(node)
|
||||
if node.left.type == "FieldName" and (node.left.value == "evt.type" or node.left.value == "syscall.type") then
|
||||
|
||||
if (node.operator == "in" or
|
||||
node.operator == "intersects" or
|
||||
node.operator == "pmatch") then
|
||||
for i, v in ipairs(node.right.elements) do
|
||||
if v.type == "BareString" then
|
||||
if node.left.value == "evt.type" then
|
||||
check_event(v.value)
|
||||
else
|
||||
check_syscall(v.value)
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if node.right.type == "BareString" then
|
||||
if node.left.value == "evt.type" then
|
||||
check_event(node.right.value)
|
||||
else
|
||||
check_syscall(node.right.value)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if (node.operator == "in" or node.operator == "intersects" or node.operator == "pmatch") then
|
||||
for i, v in ipairs(node.right.elements) do
|
||||
if v.type == "BareString" then
|
||||
if node.left.value == "evt.type" then
|
||||
check_event(v.value)
|
||||
else
|
||||
check_syscall(v.value)
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if node.right.type == "BareString" then
|
||||
if node.left.value == "evt.type" then
|
||||
check_event(node.right.value)
|
||||
else
|
||||
check_syscall(node.right.value)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
parser.traverse_ast(ast, {BinaryRelOp=1}, cb)
|
||||
parser.traverse_ast(ast, {
|
||||
BinaryRelOp = 1
|
||||
}, cb)
|
||||
end
|
||||
|
||||
-- Examine the ast and find the event types/syscalls for which the
|
||||
@@ -75,125 +72,129 @@ end
|
||||
|
||||
function sinsp_rule_utils.get_evttypes_syscalls(name, ast, source, warn_evttypes, verbose)
|
||||
|
||||
local evttypes = {}
|
||||
local syscallnums = {}
|
||||
local evtnames = {}
|
||||
local found_event = false
|
||||
local found_not = false
|
||||
local found_event_after_not = false
|
||||
local evttypes = {}
|
||||
local syscallnums = {}
|
||||
local evtnames = {}
|
||||
local found_event = false
|
||||
local found_not = false
|
||||
local found_event_after_not = false
|
||||
|
||||
function cb(node)
|
||||
if node.type == "UnaryBoolOp" then
|
||||
if node.operator == "not" then
|
||||
found_not = true
|
||||
end
|
||||
else
|
||||
if node.operator == "!=" then
|
||||
found_not = true
|
||||
end
|
||||
if node.left.type == "FieldName" and node.left.value == "evt.type" then
|
||||
found_event = true
|
||||
if found_not then
|
||||
found_event_after_not = true
|
||||
end
|
||||
if (node.operator == "in" or
|
||||
node.operator == "intersects" or
|
||||
node.operator == "pmatch") then
|
||||
for i, v in ipairs(node.right.elements) do
|
||||
if v.type == "BareString" then
|
||||
function cb(node)
|
||||
if node.type == "UnaryBoolOp" then
|
||||
if node.operator == "not" then
|
||||
found_not = true
|
||||
end
|
||||
else
|
||||
if node.operator == "!=" then
|
||||
found_not = true
|
||||
end
|
||||
if node.left.type == "FieldName" and node.left.value == "evt.type" then
|
||||
found_event = true
|
||||
if found_not then
|
||||
found_event_after_not = true
|
||||
end
|
||||
if (node.operator == "in" or node.operator == "intersects" or node.operator == "pmatch") then
|
||||
for i, v in ipairs(node.right.elements) do
|
||||
if v.type == "BareString" then
|
||||
|
||||
-- The event must be a known event
|
||||
if events[v.value] == nil and syscalls[v.value] == nil then
|
||||
error("Unknown event/syscall \""..v.value.."\" in filter: "..source)
|
||||
end
|
||||
-- The event must be a known event
|
||||
if events[v.value] == nil and syscalls[v.value] == nil then
|
||||
error("Unknown event/syscall \"" .. v.value .. "\" in filter: " .. source)
|
||||
end
|
||||
|
||||
evtnames[v.value] = 1
|
||||
if events[v.value] ~= nil then
|
||||
for id in string.gmatch(events[v.value], "%S+") do
|
||||
evttypes[id] = 1
|
||||
end
|
||||
end
|
||||
evtnames[v.value] = 1
|
||||
if events[v.value] ~= nil then
|
||||
for id in string.gmatch(events[v.value], "%S+") do
|
||||
evttypes[id] = 1
|
||||
end
|
||||
end
|
||||
|
||||
if syscalls[v.value] ~= nil then
|
||||
for id in string.gmatch(syscalls[v.value], "%S+") do
|
||||
syscallnums[id] = 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if node.right.type == "BareString" then
|
||||
if syscalls[v.value] ~= nil then
|
||||
for id in string.gmatch(syscalls[v.value], "%S+") do
|
||||
syscallnums[id] = 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if node.right.type == "BareString" then
|
||||
|
||||
-- The event must be a known event
|
||||
if events[node.right.value] == nil and syscalls[node.right.value] == nil then
|
||||
error("Unknown event/syscall \""..node.right.value.."\" in filter: "..source)
|
||||
end
|
||||
-- The event must be a known event
|
||||
if events[node.right.value] == nil and syscalls[node.right.value] == nil then
|
||||
error("Unknown event/syscall \"" .. node.right.value .. "\" in filter: " .. source)
|
||||
end
|
||||
|
||||
evtnames[node.right.value] = 1
|
||||
if events[node.right.value] ~= nil then
|
||||
for id in string.gmatch(events[node.right.value], "%S+") do
|
||||
evttypes[id] = 1
|
||||
end
|
||||
end
|
||||
evtnames[node.right.value] = 1
|
||||
if events[node.right.value] ~= nil then
|
||||
for id in string.gmatch(events[node.right.value], "%S+") do
|
||||
evttypes[id] = 1
|
||||
end
|
||||
end
|
||||
|
||||
if syscalls[node.right.value] ~= nil then
|
||||
for id in string.gmatch(syscalls[node.right.value], "%S+") do
|
||||
syscallnums[id] = 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if syscalls[node.right.value] ~= nil then
|
||||
for id in string.gmatch(syscalls[node.right.value], "%S+") do
|
||||
syscallnums[id] = 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
parser.traverse_ast(ast.filter.value, {BinaryRelOp=1, UnaryBoolOp=1} , cb)
|
||||
parser.traverse_ast(ast.filter.value, {
|
||||
BinaryRelOp = 1,
|
||||
UnaryBoolOp = 1
|
||||
}, cb)
|
||||
|
||||
if not found_event then
|
||||
if warn_evttypes == true then
|
||||
io.stderr:write("Rule "..name..": warning (no-evttype):\n")
|
||||
io.stderr:write(source.."\n")
|
||||
io.stderr:write(" did not contain any evt.type restriction, meaning it will run for all event types.\n")
|
||||
io.stderr:write(" This has a significant performance penalty. Consider adding an evt.type restriction if possible.\n")
|
||||
end
|
||||
evttypes = {}
|
||||
syscallnums = {}
|
||||
evtnames = {}
|
||||
end
|
||||
if not found_event then
|
||||
if warn_evttypes == true then
|
||||
io.stderr:write("Rule " .. name .. ": warning (no-evttype):\n")
|
||||
io.stderr:write(source .. "\n")
|
||||
io.stderr:write(
|
||||
" did not contain any evt.type restriction, meaning it will run for all event types.\n")
|
||||
io.stderr:write(
|
||||
" This has a significant performance penalty. Consider adding an evt.type restriction if possible.\n")
|
||||
end
|
||||
evttypes = {}
|
||||
syscallnums = {}
|
||||
evtnames = {}
|
||||
end
|
||||
|
||||
if found_event_after_not then
|
||||
if warn_evttypes == true then
|
||||
io.stderr:write("Rule "..name..": warning (trailing-evttype):\n")
|
||||
io.stderr:write(source.."\n")
|
||||
io.stderr:write(" does not have all evt.type restrictions at the beginning of the condition,\n")
|
||||
io.stderr:write(" or uses a negative match (i.e. \"not\"/\"!=\") for some evt.type restriction.\n")
|
||||
io.stderr:write(" This has a performance penalty, as the rule can not be limited to specific event types.\n")
|
||||
io.stderr:write(" Consider moving all evt.type restrictions to the beginning of the rule and/or\n")
|
||||
io.stderr:write(" replacing negative matches with positive matches if possible.\n")
|
||||
end
|
||||
evttypes = {}
|
||||
syscallnums = {}
|
||||
evtnames = {}
|
||||
end
|
||||
if found_event_after_not then
|
||||
if warn_evttypes == true then
|
||||
io.stderr:write("Rule " .. name .. ": warning (trailing-evttype):\n")
|
||||
io.stderr:write(source .. "\n")
|
||||
io.stderr:write(" does not have all evt.type restrictions at the beginning of the condition,\n")
|
||||
io.stderr:write(" or uses a negative match (i.e. \"not\"/\"!=\") for some evt.type restriction.\n")
|
||||
io.stderr:write(
|
||||
" This has a performance penalty, as the rule can not be limited to specific event types.\n")
|
||||
io.stderr:write(" Consider moving all evt.type restrictions to the beginning of the rule and/or\n")
|
||||
io.stderr:write(" replacing negative matches with positive matches if possible.\n")
|
||||
end
|
||||
evttypes = {}
|
||||
syscallnums = {}
|
||||
evtnames = {}
|
||||
end
|
||||
|
||||
evtnames_only = {}
|
||||
local num_evtnames = 0
|
||||
for name, dummy in pairs(evtnames) do
|
||||
table.insert(evtnames_only, name)
|
||||
num_evtnames = num_evtnames + 1
|
||||
end
|
||||
evtnames_only = {}
|
||||
local num_evtnames = 0
|
||||
for name, dummy in pairs(evtnames) do
|
||||
table.insert(evtnames_only, name)
|
||||
num_evtnames = num_evtnames + 1
|
||||
end
|
||||
|
||||
if num_evtnames == 0 then
|
||||
table.insert(evtnames_only, "all")
|
||||
end
|
||||
if num_evtnames == 0 then
|
||||
table.insert(evtnames_only, "all")
|
||||
end
|
||||
|
||||
table.sort(evtnames_only)
|
||||
table.sort(evtnames_only)
|
||||
|
||||
if verbose then
|
||||
io.stderr:write("Event types/Syscalls for rule "..name..": "..table.concat(evtnames_only, ",").."\n")
|
||||
end
|
||||
if verbose then
|
||||
io.stderr:write("Event types/Syscalls for rule " .. name .. ": " .. table.concat(evtnames_only, ",") .. "\n")
|
||||
end
|
||||
|
||||
return evttypes, syscallnums
|
||||
return evttypes, syscallnums
|
||||
end
|
||||
|
||||
return sinsp_rule_utils
|
||||
|
||||
@@ -26,14 +26,15 @@ extern "C" {
|
||||
#include "falco_engine.h"
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
const static struct luaL_Reg ll_falco_rules[] =
|
||||
{
|
||||
{"clear_filters", &falco_rules::clear_filters},
|
||||
{"add_filter", &falco_rules::add_filter},
|
||||
{"add_k8s_audit_filter", &falco_rules::add_k8s_audit_filter},
|
||||
{"enable_rule", &falco_rules::enable_rule},
|
||||
{"engine_version", &falco_rules::engine_version},
|
||||
{NULL, NULL}};
|
||||
const static struct luaL_reg ll_falco_rules [] =
|
||||
{
|
||||
{"clear_filters", &falco_rules::clear_filters},
|
||||
{"add_filter", &falco_rules::add_filter},
|
||||
{"add_k8s_audit_filter", &falco_rules::add_k8s_audit_filter},
|
||||
{"enable_rule", &falco_rules::enable_rule},
|
||||
{"engine_version", &falco_rules::engine_version},
|
||||
{NULL,NULL}
|
||||
};
|
||||
|
||||
falco_rules::falco_rules(sinsp* inspector,
|
||||
falco_engine *engine,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco Authors.
|
||||
# Copyright (C) 2019 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
|
||||
@@ -11,132 +11,10 @@
|
||||
# specific language governing permissions and limitations under the License.
|
||||
#
|
||||
|
||||
configure_file(config_falco.h.in config_falco.h)
|
||||
configure_file("${SYSDIG_SOURCE_DIR}/userspace/sysdig/config_sysdig.h.in" config_sysdig.h)
|
||||
|
||||
set(
|
||||
FALCO_SOURCES
|
||||
configuration.cpp
|
||||
logger.cpp
|
||||
falco_outputs.cpp
|
||||
outputs_file.cpp
|
||||
outputs_program.cpp
|
||||
outputs_stdout.cpp
|
||||
outputs_syslog.cpp
|
||||
event_drops.cpp
|
||||
statsfilewriter.cpp
|
||||
falco.cpp
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/libsinsp/fields_info.cpp"
|
||||
)
|
||||
|
||||
set(
|
||||
FALCO_INCLUDE_DIRECTORIES
|
||||
"${PROJECT_SOURCE_DIR}/userspace/engine"
|
||||
"${PROJECT_BINARY_DIR}/userspace/falco"
|
||||
"${PROJECT_BINARY_DIR}/driver/src"
|
||||
"${STRING_VIEW_LITE_INCLUDE}"
|
||||
"${YAMLCPP_INCLUDE_DIR}"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
"${DRAIOS_DEPENDENCIES_DIR}/yaml-${DRAIOS_YAML_VERSION}/target/include"
|
||||
)
|
||||
|
||||
set(
|
||||
FALCO_DEPENDENCIES
|
||||
string-view-lite
|
||||
libyaml
|
||||
b64
|
||||
luajit
|
||||
lpeg
|
||||
lyaml
|
||||
)
|
||||
|
||||
set(
|
||||
FALCO_LIBRARIES
|
||||
falco_engine
|
||||
sinsp
|
||||
"${LIBYAML_LIB}"
|
||||
"${YAMLCPP_LIB}"
|
||||
)
|
||||
|
||||
if(USE_BUNDLED_DEPS)
|
||||
list(APPEND FALCO_DEPENDENCIES yamlcpp)
|
||||
endif()
|
||||
|
||||
if(NOT MINIMAL_BUILD)
|
||||
list(
|
||||
APPEND FALCO_SOURCES
|
||||
outputs_grpc.cpp
|
||||
outputs_http.cpp
|
||||
webserver.cpp
|
||||
grpc_context.cpp
|
||||
grpc_server_impl.cpp
|
||||
grpc_request_context.cpp
|
||||
grpc_server.cpp
|
||||
grpc_context.cpp
|
||||
grpc_server_impl.cpp
|
||||
${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/version.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/outputs.grpc.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/outputs.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/schema.pb.cc
|
||||
)
|
||||
|
||||
list(
|
||||
APPEND FALCO_INCLUDE_DIRECTORIES
|
||||
"${CIVETWEB_INCLUDE_DIR}"
|
||||
"${OPENSSL_INCLUDE_DIR}"
|
||||
"${GRPC_INCLUDE}"
|
||||
"${GRPCPP_INCLUDE}"
|
||||
"${PROTOBUF_INCLUDE}"
|
||||
)
|
||||
|
||||
list(APPEND FALCO_DEPENDENCIES civetweb)
|
||||
|
||||
list(
|
||||
APPEND FALCO_LIBRARIES
|
||||
"${GPR_LIB}"
|
||||
"${GRPC_LIB}"
|
||||
"${GRPCPP_LIB}"
|
||||
"${PROTOBUF_LIB}"
|
||||
"${OPENSSL_LIBRARY_SSL}"
|
||||
"${OPENSSL_LIBRARY_CRYPTO}"
|
||||
"${LIBYAML_LIB}"
|
||||
"${YAMLCPP_LIB}"
|
||||
"${CIVETWEB_LIB}"
|
||||
)
|
||||
endif()
|
||||
|
||||
add_executable(
|
||||
falco
|
||||
${FALCO_SOURCES}
|
||||
)
|
||||
|
||||
add_dependencies(falco ${FALCO_DEPENDENCIES})
|
||||
|
||||
target_link_libraries(
|
||||
falco
|
||||
${FALCO_LIBRARIES}
|
||||
)
|
||||
|
||||
target_include_directories(
|
||||
falco
|
||||
PUBLIC
|
||||
${FALCO_INCLUDE_DIRECTORIES}
|
||||
)
|
||||
|
||||
if(NOT MINIMAL_BUILD)
|
||||
add_custom_command(
|
||||
TARGET falco
|
||||
COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/verify_engine_fields.sh ${CMAKE_SOURCE_DIR}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMENT "Comparing engine fields checksum in falco_engine.h to actual fields"
|
||||
)
|
||||
else()
|
||||
message(STATUS "Skipping engine fields checksum when building the minimal Falco.")
|
||||
endif()
|
||||
|
||||
if(NOT MINIMAL_BUILD)
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/version.pb.cc
|
||||
@@ -147,30 +25,89 @@ if(NOT MINIMAL_BUILD)
|
||||
${CMAKE_CURRENT_BINARY_DIR}/outputs.pb.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/schema.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/schema.pb.h
|
||||
COMMENT "Generate gRPC API"
|
||||
# Falco gRPC Version API
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/version.proto
|
||||
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --cpp_out=. ${CMAKE_CURRENT_SOURCE_DIR}/version.proto
|
||||
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --grpc_out=. --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/version.proto
|
||||
# Falco gRPC Outputs API
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/outputs.proto
|
||||
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --cpp_out=. ${CMAKE_CURRENT_SOURCE_DIR}/outputs.proto
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/schema.proto
|
||||
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --grpc_out=. --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/outputs.proto
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
COMMENT "Generate gRPC API"
|
||||
# Falco gRPC Version API
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/version.proto
|
||||
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --cpp_out=. ${CMAKE_CURRENT_SOURCE_DIR}/version.proto
|
||||
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --grpc_out=. --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/version.proto
|
||||
# Falco gRPC Outputs API
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/outputs.proto
|
||||
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --cpp_out=. ${CMAKE_CURRENT_SOURCE_DIR}/outputs.proto
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/schema.proto
|
||||
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --grpc_out=. --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/outputs.proto
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
add_executable(
|
||||
falco
|
||||
configuration.cpp
|
||||
logger.cpp
|
||||
falco_outputs.cpp
|
||||
event_drops.cpp
|
||||
statsfilewriter.cpp
|
||||
falco.cpp
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/sysdig/fields_info.cpp"
|
||||
webserver.cpp
|
||||
grpc_context.cpp
|
||||
grpc_server_impl.cpp
|
||||
grpc_request_context.cpp
|
||||
grpc_server.cpp
|
||||
${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/version.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/outputs.grpc.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/outputs.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/schema.pb.cc)
|
||||
|
||||
add_dependencies(falco civetweb string-view-lite)
|
||||
|
||||
if(USE_BUNDLED_DEPS)
|
||||
add_dependencies(falco yamlcpp)
|
||||
endif()
|
||||
|
||||
# strip the Falco binary when releasing using musl
|
||||
if(MUSL_OPTIMIZED_BUILD AND CMAKE_BUILD_TYPE STREQUAL "release")
|
||||
add_custom_command(
|
||||
TARGET falco
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_STRIP} --strip-unneeded falco
|
||||
COMMENT "Strip the Falco binary when releasing the musl build"
|
||||
)
|
||||
endif()
|
||||
target_include_directories(
|
||||
falco
|
||||
PUBLIC
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/sysdig"
|
||||
"${PROJECT_SOURCE_DIR}/userspace/engine"
|
||||
"${PROJECT_BINARY_DIR}/userspace/falco"
|
||||
"${PROJECT_BINARY_DIR}/driver/src"
|
||||
"${STRING_VIEW_LITE_INCLUDE}"
|
||||
"${YAMLCPP_INCLUDE_DIR}"
|
||||
"${CIVETWEB_INCLUDE_DIR}"
|
||||
"${GRPC_INCLUDE}"
|
||||
"${GRPCPP_INCLUDE}"
|
||||
"${PROTOBUF_INCLUDE}"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
"${DRAIOS_DEPENDENCIES_DIR}/yaml-${DRAIOS_YAML_VERSION}/target/include")
|
||||
|
||||
target_link_libraries(
|
||||
falco
|
||||
falco_engine
|
||||
sinsp
|
||||
"${GPR_LIB}"
|
||||
"${GRPC_LIB}"
|
||||
"${GRPCPP_LIB}"
|
||||
"${PROTOBUF_LIB}"
|
||||
"${LIBYAML_LIB}"
|
||||
"${YAMLCPP_LIB}"
|
||||
"${CIVETWEB_LIB}")
|
||||
|
||||
configure_file(config_falco.h.in config_falco.h)
|
||||
|
||||
add_custom_command(
|
||||
TARGET falco
|
||||
COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/verify_engine_fields.sh ${CMAKE_SOURCE_DIR} ${OPENSSL_BINARY}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMENT "Comparing engine fields checksum in falco_engine.h to actual fields")
|
||||
|
||||
# add_custom_target(verify_engine_fields DEPENDS verify_engine_fields.sh falco_engine.h)
|
||||
|
||||
# add_dependencies(verify_engine_fields falco)
|
||||
|
||||
install(TARGETS falco DESTINATION ${FALCO_BIN_DIR})
|
||||
install(
|
||||
DIRECTORY lua
|
||||
DESTINATION ${FALCO_SHARE_DIR}
|
||||
FILES_MATCHING
|
||||
PATTERN *.lua)
|
||||
|
||||
@@ -25,9 +25,11 @@ limitations under the License.
|
||||
#define FALCO_VERSION_PRERELEASE "@FALCO_VERSION_PRERELEASE@"
|
||||
#define FALCO_VERSION_BUILD "@FALCO_VERSION_BUILD@"
|
||||
|
||||
#define FALCO_LUA_DIR "${CMAKE_INSTALL_PREFIX}/${FALCO_SHARE_DIR}/lua/"
|
||||
#define FALCO_SOURCE_DIR "${PROJECT_SOURCE_DIR}"
|
||||
#define FALCO_SOURCE_CONF_FILE "${PROJECT_SOURCE_DIR}/falco.yaml"
|
||||
#define FALCO_INSTALL_CONF_FILE "/etc/falco/falco.yaml"
|
||||
#define FALCO_SOURCE_LUA_DIR "${PROJECT_SOURCE_DIR}/userspace/falco/lua/"
|
||||
|
||||
#define PROBE_NAME "@PROBE_NAME@"
|
||||
#define DRIVER_VERSION "@PROBE_VERSION@"
|
||||
@@ -47,6 +47,16 @@ falco_configuration::~falco_configuration()
|
||||
}
|
||||
}
|
||||
|
||||
// If we don't have a configuration file, we just use stdout output and all other defaults
|
||||
void falco_configuration::init(list<string> &cmdline_options)
|
||||
{
|
||||
init_cmdline_options(cmdline_options);
|
||||
|
||||
falco_outputs::output_config stdout_output;
|
||||
stdout_output.name = "stdout";
|
||||
m_outputs.push_back(stdout_output);
|
||||
}
|
||||
|
||||
void falco_configuration::init(string conf_filename, list<string> &cmdline_options)
|
||||
{
|
||||
string m_config_file = conf_filename;
|
||||
@@ -71,7 +81,7 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
|
||||
m_json_output = m_config->get_scalar<bool>("json_output", false);
|
||||
m_json_include_output_property = m_config->get_scalar<bool>("json_include_output_property", true);
|
||||
|
||||
falco::outputs::config file_output;
|
||||
falco_outputs::output_config file_output;
|
||||
file_output.name = "file";
|
||||
if(m_config->get_scalar<bool>("file_output", "enabled", false))
|
||||
{
|
||||
@@ -89,21 +99,21 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
|
||||
m_outputs.push_back(file_output);
|
||||
}
|
||||
|
||||
falco::outputs::config stdout_output;
|
||||
falco_outputs::output_config stdout_output;
|
||||
stdout_output.name = "stdout";
|
||||
if(m_config->get_scalar<bool>("stdout_output", "enabled", false))
|
||||
{
|
||||
m_outputs.push_back(stdout_output);
|
||||
}
|
||||
|
||||
falco::outputs::config syslog_output;
|
||||
falco_outputs::output_config syslog_output;
|
||||
syslog_output.name = "syslog";
|
||||
if(m_config->get_scalar<bool>("syslog_output", "enabled", false))
|
||||
{
|
||||
m_outputs.push_back(syslog_output);
|
||||
}
|
||||
|
||||
falco::outputs::config program_output;
|
||||
falco_outputs::output_config program_output;
|
||||
program_output.name = "program";
|
||||
if(m_config->get_scalar<bool>("program_output", "enabled", false))
|
||||
{
|
||||
@@ -121,7 +131,7 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
|
||||
m_outputs.push_back(program_output);
|
||||
}
|
||||
|
||||
falco::outputs::config http_output;
|
||||
falco_outputs::output_config http_output;
|
||||
http_output.name = "http";
|
||||
if(m_config->get_scalar<bool>("http_output", "enabled", false))
|
||||
{
|
||||
@@ -149,7 +159,7 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
|
||||
m_grpc_cert_chain = m_config->get_scalar<string>("grpc", "cert_chain", "/etc/falco/certs/server.crt");
|
||||
m_grpc_root_certs = m_config->get_scalar<string>("grpc", "root_certs", "/etc/falco/certs/ca.crt");
|
||||
|
||||
falco::outputs::config grpc_output;
|
||||
falco_outputs::output_config grpc_output;
|
||||
grpc_output.name = "grpc";
|
||||
// gRPC output is enabled only if gRPC server is enabled too
|
||||
if(m_config->get_scalar<bool>("grpc_output", "enabled", true) && m_grpc_enabled)
|
||||
@@ -166,8 +176,6 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
|
||||
|
||||
falco_logger::set_level(m_log_level);
|
||||
|
||||
m_output_timeout = m_config->get_scalar<uint32_t>("output_timeout", 2000);
|
||||
|
||||
m_notifications_rate = m_config->get_scalar<uint32_t>("outputs", "rate", 1);
|
||||
m_notifications_max_burst = m_config->get_scalar<uint32_t>("outputs", "max_burst", 1000);
|
||||
|
||||
@@ -338,4 +346,4 @@ void falco_configuration::set_cmdline_option(const string &opt)
|
||||
{
|
||||
m_config->set_scalar(keyval.first, keyval.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
{
|
||||
m_path = path;
|
||||
YAML::Node config;
|
||||
std::vector<falco::outputs::config> outputs;
|
||||
std::vector<falco_outputs::output_config> outputs;
|
||||
try
|
||||
{
|
||||
m_root = YAML::LoadFile(path);
|
||||
@@ -196,7 +196,7 @@ public:
|
||||
bool m_json_output;
|
||||
bool m_json_include_output_property;
|
||||
std::string m_log_level;
|
||||
std::vector<falco::outputs::config> m_outputs;
|
||||
std::vector<falco_outputs::output_config> m_outputs;
|
||||
uint32_t m_notifications_rate;
|
||||
uint32_t m_notifications_max_burst;
|
||||
|
||||
@@ -204,7 +204,6 @@ public:
|
||||
|
||||
bool m_buffered_outputs;
|
||||
bool m_time_format_iso_8601;
|
||||
uint32_t m_output_timeout;
|
||||
|
||||
bool m_grpc_enabled;
|
||||
uint32_t m_grpc_threadiness;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
Copyright (C) 2019 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.
|
||||
@@ -15,7 +15,6 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
#include "event_drops.h"
|
||||
#include "falco_common.h"
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
syscall_evt_drop_mgr::syscall_evt_drop_mgr():
|
||||
@@ -138,7 +137,7 @@ bool syscall_evt_drop_mgr::perform_actions(uint64_t now, scap_stats &delta, bool
|
||||
|
||||
case ACT_ALERT:
|
||||
m_outputs->handle_msg(now,
|
||||
falco_common::PRIORITY_CRITICAL,
|
||||
falco_outputs::PRIORITY_CRITICAL,
|
||||
msg,
|
||||
rule,
|
||||
output_fields);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
Copyright (C) 2019 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.
|
||||
@@ -36,17 +36,15 @@ limitations under the License.
|
||||
#include "logger.h"
|
||||
#include "utils.h"
|
||||
#include "chisel.h"
|
||||
#include "fields_info.h"
|
||||
#include "sysdig.h"
|
||||
|
||||
#include "event_drops.h"
|
||||
#include "configuration.h"
|
||||
#include "falco_engine.h"
|
||||
#include "config_falco.h"
|
||||
#include "statsfilewriter.h"
|
||||
#ifndef MINIMAL_BUILD
|
||||
#include "webserver.h"
|
||||
#include "grpc_server.h"
|
||||
#endif
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
typedef function<void(sinsp* inspector)> open_t;
|
||||
@@ -86,7 +84,6 @@ static void usage()
|
||||
" -h, --help Print this page\n"
|
||||
" -c Configuration file (default " FALCO_SOURCE_CONF_FILE ", " FALCO_INSTALL_CONF_FILE ")\n"
|
||||
" -A Monitor all events, including those with EF_DROP_SIMPLE_CONS flag.\n"
|
||||
" --alternate-lua-dir <path> Specify an alternate path for loading Falco lua files\n"
|
||||
" -b, --print-base64 Print data buffers in base64.\n"
|
||||
" This is useful for encoding binary data that needs to be used over media designed to.\n"
|
||||
" --cri <path> Path to CRI socket for container metadata.\n"
|
||||
@@ -107,7 +104,6 @@ static void usage()
|
||||
" Can not be specified with -t.\n"
|
||||
" -e <events_file> Read the events from <events_file> (in .scap format for sinsp events, or jsonl for\n"
|
||||
" k8s audit events) instead of tapping into live.\n"
|
||||
#ifndef MINIMAL_BUILD
|
||||
" -k <url>, --k8s-api <url>\n"
|
||||
" Enable Kubernetes support by connecting to the API server specified as argument.\n"
|
||||
" E.g. \"http://admin:password@127.0.0.1:8080\".\n"
|
||||
@@ -121,18 +117,15 @@ static void usage()
|
||||
" for this option, it will be interpreted as the name of a file containing bearer token.\n"
|
||||
" Note that the format of this command-line option prohibits use of files whose names contain\n"
|
||||
" ':' or '#' characters in the file name.\n"
|
||||
#endif
|
||||
" -L Show the name and description of all rules and exit.\n"
|
||||
" -l <rule> Show the name and description of the rule with name <rule> and exit.\n"
|
||||
" --list [<source>] List all defined fields. If <source> is provided, only list those fields for\n"
|
||||
" the source <source>. Current values for <source> are \"syscall\", \"k8s_audit\"\n"
|
||||
#ifndef MINIMAL_BUILD
|
||||
" -m <url[,marathon_url]>, --mesos-api <url[,marathon_url]>\n"
|
||||
" Enable Mesos support by connecting to the API server\n"
|
||||
" specified as argument. E.g. \"http://admin:password@127.0.0.1:5050\".\n"
|
||||
" Marathon url is optional and defaults to Mesos address, port 8080.\n"
|
||||
" The API servers can also be specified via the environment variable FALCO_MESOS_API.\n"
|
||||
#endif
|
||||
" -M <num_seconds> Stop collecting after <num_seconds> reached.\n"
|
||||
" -N When used with --list, only print field names.\n"
|
||||
" -o, --option <key>=<val> Set the value of option <key> to <val>. Overrides values in configuration file.\n"
|
||||
@@ -192,7 +185,6 @@ static void display_fatal_err(const string &msg)
|
||||
// Splitting into key=value or key.subkey=value will be handled by configuration class.
|
||||
std::list<string> cmdline_options;
|
||||
|
||||
#ifndef MINIMAL_BUILD
|
||||
// Read a jsonl file containing k8s audit events and pass each to the engine.
|
||||
void read_k8s_audit_trace_file(falco_engine *engine,
|
||||
falco_outputs *outputs,
|
||||
@@ -221,7 +213,6 @@ void read_k8s_audit_trace_file(falco_engine *engine,
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static std::string read_file(std::string filename)
|
||||
{
|
||||
@@ -438,11 +429,9 @@ int falco_init(int argc, char **argv)
|
||||
bool verbose = false;
|
||||
bool names_only = false;
|
||||
bool all_events = false;
|
||||
#ifndef MINIMAL_BUILD
|
||||
string* k8s_api = 0;
|
||||
string* k8s_api_cert = 0;
|
||||
string* mesos_api = 0;
|
||||
#endif
|
||||
string output_format = "";
|
||||
uint32_t snaplen = 0;
|
||||
bool replace_container_info = false;
|
||||
@@ -472,45 +461,42 @@ int falco_init(int argc, char **argv)
|
||||
double duration;
|
||||
scap_stats cstats;
|
||||
|
||||
#ifndef MINIMAL_BUILD
|
||||
falco_webserver webserver;
|
||||
falco::grpc::server grpc_server;
|
||||
std::thread grpc_server_thread;
|
||||
#endif
|
||||
|
||||
static struct option long_options[] =
|
||||
{
|
||||
{"alternate-lua-dir", required_argument, 0},
|
||||
{"cri", required_argument, 0},
|
||||
{"daemon", no_argument, 0, 'd'},
|
||||
{"disable-cri-async", no_argument, 0, 0},
|
||||
{"disable-source", required_argument, 0},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"ignored-events", no_argument, 0, 'i'},
|
||||
{"k8s-api-cert", required_argument, 0, 'K'},
|
||||
{"k8s-api", required_argument, 0, 'k'},
|
||||
{"list", optional_argument, 0},
|
||||
{"mesos-api", required_argument, 0, 'm'},
|
||||
{"option", required_argument, 0, 'o'},
|
||||
{"pidfile", required_argument, 0, 'P'},
|
||||
{"print-base64", no_argument, 0, 'b'},
|
||||
{"print", required_argument, 0, 'p'},
|
||||
{"snaplen", required_argument, 0, 'S'},
|
||||
{"stats-interval", required_argument, 0},
|
||||
{"support", no_argument, 0},
|
||||
{"unbuffered", no_argument, 0, 'U'},
|
||||
{"userspace", no_argument, 0, 'u'},
|
||||
{"validate", required_argument, 0, 'V'},
|
||||
{"version", no_argument, 0, 0},
|
||||
{"writefile", required_argument, 0, 'w'},
|
||||
{0, 0, 0, 0}};
|
||||
{
|
||||
{"cri", required_argument, 0},
|
||||
{"daemon", no_argument, 0, 'd'},
|
||||
{"disable-cri-async", no_argument, 0, 0},
|
||||
{"disable-source", required_argument, 0},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"ignored-events", no_argument, 0, 'i'},
|
||||
{"k8s-api-cert", required_argument, 0, 'K'},
|
||||
{"k8s-api", required_argument, 0, 'k'},
|
||||
{"list", optional_argument, 0},
|
||||
{"mesos-api", required_argument, 0, 'm'},
|
||||
{"option", required_argument, 0, 'o'},
|
||||
{"pidfile", required_argument, 0, 'P'},
|
||||
{"print-base64", no_argument, 0, 'b'},
|
||||
{"print", required_argument, 0, 'p'},
|
||||
{"snaplen", required_argument, 0, 'S'},
|
||||
{"stats-interval", required_argument, 0},
|
||||
{"support", no_argument, 0},
|
||||
{"unbuffered", no_argument, 0, 'U'},
|
||||
{"userspace", no_argument, 0, 'u'},
|
||||
{"validate", required_argument, 0, 'V'},
|
||||
{"version", no_argument, 0, 0},
|
||||
{"writefile", required_argument, 0, 'w'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
set<string> disabled_rule_substrings;
|
||||
string substring;
|
||||
string all_rules = "";
|
||||
string alternate_lua_dir = FALCO_ENGINE_SOURCE_LUA_DIR;
|
||||
set<string> disabled_rule_tags;
|
||||
set<string> enabled_rule_tags;
|
||||
|
||||
@@ -544,10 +530,8 @@ int falco_init(int argc, char **argv)
|
||||
break;
|
||||
case 'e':
|
||||
trace_filename = optarg;
|
||||
#ifndef MINIMAL_BUILD
|
||||
k8s_api = new string();
|
||||
mesos_api = new string();
|
||||
#endif
|
||||
break;
|
||||
case 'F':
|
||||
list_flds = optarg;
|
||||
@@ -555,25 +539,21 @@ int falco_init(int argc, char **argv)
|
||||
case 'i':
|
||||
print_ignored_events = true;
|
||||
break;
|
||||
#ifndef MINIMAL_BUILD
|
||||
case 'k':
|
||||
k8s_api = new string(optarg);
|
||||
break;
|
||||
case 'K':
|
||||
k8s_api_cert = new string(optarg);
|
||||
break;
|
||||
#endif
|
||||
case 'L':
|
||||
describe_all_rules = true;
|
||||
break;
|
||||
case 'l':
|
||||
describe_rule = optarg;
|
||||
break;
|
||||
#ifndef MINIMAL_BUILD
|
||||
case 'm':
|
||||
mesos_api = new string(optarg);
|
||||
break;
|
||||
#endif
|
||||
case 'M':
|
||||
duration_to_tot = atoi(optarg);
|
||||
if(duration_to_tot <= 0)
|
||||
@@ -688,16 +668,6 @@ int falco_init(int argc, char **argv)
|
||||
disable_sources.insert(optarg);
|
||||
}
|
||||
}
|
||||
else if (string(long_options[long_index].name)== "alternate-lua-dir")
|
||||
{
|
||||
if(optarg != NULL)
|
||||
{
|
||||
alternate_lua_dir = optarg;
|
||||
if (alternate_lua_dir.back() != '/') {
|
||||
alternate_lua_dir += '/';
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -733,7 +703,7 @@ int falco_init(int argc, char **argv)
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
engine = new falco_engine(true, alternate_lua_dir);
|
||||
engine = new falco_engine();
|
||||
engine->set_inspector(inspector);
|
||||
engine->set_extra(output_format, replace_container_info);
|
||||
|
||||
@@ -762,7 +732,8 @@ int falco_init(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
outputs = new falco_outputs();
|
||||
outputs = new falco_outputs(engine);
|
||||
outputs->set_inspector(inspector);
|
||||
|
||||
// Some combinations of arguments are not allowed.
|
||||
if (daemon && pidfilename == "") {
|
||||
@@ -794,7 +765,7 @@ int falco_init(int argc, char **argv)
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::invalid_argument("You must create a config file at " FALCO_SOURCE_CONF_FILE ", " FALCO_INSTALL_CONF_FILE " or by passing -c\n");
|
||||
conf_filename = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -836,7 +807,12 @@ int falco_init(int argc, char **argv)
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Could not find configuration file at " + conf_filename);
|
||||
config.init(cmdline_options);
|
||||
falco_logger::set_time_format_iso_8601(config.m_time_format_iso_8601);
|
||||
|
||||
// log after config init because config determines where logs go
|
||||
falco_logger::log(LOG_INFO, "Falco version " + std::string(FALCO_VERSION) + " (driver version " + std::string(DRIVER_VERSION) + ")\n");
|
||||
falco_logger::log(LOG_INFO, "Falco initialized. No configuration file found, proceeding with defaults\n");
|
||||
}
|
||||
|
||||
if (rules_filenames.size())
|
||||
@@ -965,9 +941,9 @@ int falco_init(int argc, char **argv)
|
||||
hostname = c_hostname;
|
||||
}
|
||||
|
||||
|
||||
outputs->init(config.m_json_output,
|
||||
config.m_json_include_output_property,
|
||||
config.m_output_timeout,
|
||||
config.m_notifications_rate, config.m_notifications_max_burst,
|
||||
config.m_buffered_outputs,
|
||||
config.m_time_format_iso_8601,
|
||||
@@ -1098,12 +1074,6 @@ int falco_init(int argc, char **argv)
|
||||
|
||||
if(!trace_is_scap)
|
||||
{
|
||||
#ifdef MINIMAL_BUILD
|
||||
// Note that the webserver is not available when MINIMAL_BUILD is defined.
|
||||
fprintf(stderr, "Cannot use k8s audit events trace file with a minimal Falco build");
|
||||
result = EXIT_FAILURE;
|
||||
goto exit;
|
||||
#else
|
||||
try {
|
||||
string line;
|
||||
nlohmann::json j;
|
||||
@@ -1128,7 +1098,6 @@ int falco_init(int argc, char **argv)
|
||||
result = EXIT_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1174,14 +1143,11 @@ int falco_init(int argc, char **argv)
|
||||
// Try to insert the Falco kernel module
|
||||
if(system("modprobe " PROBE_NAME " > /dev/null 2> /dev/null"))
|
||||
{
|
||||
falco_logger::log(LOG_ERR, "Unable to load the driver.\n");
|
||||
falco_logger::log(LOG_ERR, "Unable to load the driver. Exiting.\n");
|
||||
}
|
||||
open_f(inspector);
|
||||
}
|
||||
else
|
||||
{
|
||||
rethrow_exception(current_exception());
|
||||
}
|
||||
rethrow_exception(current_exception());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1199,7 +1165,6 @@ int falco_init(int argc, char **argv)
|
||||
|
||||
duration = ((double)clock()) / CLOCKS_PER_SEC;
|
||||
|
||||
#ifndef MINIMAL_BUILD
|
||||
//
|
||||
// Run k8s, if required
|
||||
//
|
||||
@@ -1283,15 +1248,12 @@ int falco_init(int argc, char **argv)
|
||||
grpc_server.run();
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
if(!trace_filename.empty() && !trace_is_scap)
|
||||
{
|
||||
#ifndef MINIMAL_BUILD
|
||||
read_k8s_audit_trace_file(engine,
|
||||
outputs,
|
||||
trace_filename);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1337,14 +1299,12 @@ int falco_init(int argc, char **argv)
|
||||
inspector->close();
|
||||
engine->print_stats();
|
||||
sdropmgr.print_stats();
|
||||
#ifndef MINIMAL_BUILD
|
||||
webserver.stop();
|
||||
if(grpc_server_thread.joinable())
|
||||
{
|
||||
grpc_server.shutdown();
|
||||
grpc_server_thread.join();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
catch(exception &e)
|
||||
{
|
||||
@@ -1352,14 +1312,12 @@ int falco_init(int argc, char **argv)
|
||||
|
||||
result = EXIT_FAILURE;
|
||||
|
||||
#ifndef MINIMAL_BUILD
|
||||
webserver.stop();
|
||||
if(grpc_server_thread.joinable())
|
||||
{
|
||||
grpc_server.shutdown();
|
||||
grpc_server_thread.join();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
Copyright (C) 2019 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.
|
||||
@@ -14,9 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef MINIMAL_BUILD
|
||||
#include <google/protobuf/util/time_util.h>
|
||||
#endif
|
||||
|
||||
#include "falco_outputs.h"
|
||||
|
||||
@@ -24,22 +22,20 @@ limitations under the License.
|
||||
|
||||
#include "formats.h"
|
||||
#include "logger.h"
|
||||
#include "watchdog.h"
|
||||
|
||||
#include "outputs_file.h"
|
||||
#include "outputs_program.h"
|
||||
#include "outputs_stdout.h"
|
||||
#include "outputs_syslog.h"
|
||||
#ifndef MINIMAL_BUILD
|
||||
#include "outputs_http.h"
|
||||
#include "outputs_grpc.h"
|
||||
#endif
|
||||
|
||||
#include "falco_outputs_queue.h"
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
using namespace std;
|
||||
|
||||
falco_outputs::falco_outputs():
|
||||
const static struct luaL_reg ll_falco_outputs [] =
|
||||
{
|
||||
{"handle_http", &falco_outputs::handle_http},
|
||||
{"handle_grpc", &falco_outputs::handle_grpc},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
falco_outputs::falco_outputs(falco_engine *engine):
|
||||
m_falco_engine(engine),
|
||||
m_initialized(false),
|
||||
m_buffered(true),
|
||||
m_json_output(false),
|
||||
@@ -50,37 +46,52 @@ falco_outputs::falco_outputs():
|
||||
|
||||
falco_outputs::~falco_outputs()
|
||||
{
|
||||
// Note: The assert()s in this destructor were previously places where
|
||||
// exceptions were thrown. C++11 doesn't allow destructors to
|
||||
// emit exceptions; if they're thrown, they'll trigger a call
|
||||
// to 'terminate()'. To maintain similar behavior, the exceptions
|
||||
// were replace with calls to 'assert()'
|
||||
if(m_initialized)
|
||||
{
|
||||
this->stop_worker();
|
||||
for(auto o : m_outputs)
|
||||
lua_getglobal(m_ls, m_lua_output_cleanup.c_str());
|
||||
if(!lua_isfunction(m_ls, -1))
|
||||
{
|
||||
delete o;
|
||||
falco_logger::log(LOG_ERR, std::string("No function ") + m_lua_output_cleanup + " found. ");
|
||||
assert(nullptr == "Missing lua cleanup function in ~falco_outputs");
|
||||
}
|
||||
|
||||
if(lua_pcall(m_ls, 0, 0, 0) != 0)
|
||||
{
|
||||
const char *lerr = lua_tostring(m_ls, -1);
|
||||
falco_logger::log(LOG_ERR, std::string("lua_pcall failed, err: ") + lerr);
|
||||
assert(nullptr == "lua_pcall failed in ~falco_outputs");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void falco_outputs::init(bool json_output,
|
||||
bool json_include_output_property,
|
||||
uint32_t timeout,
|
||||
uint32_t rate, uint32_t max_burst, bool buffered,
|
||||
bool time_format_iso_8601, std::string hostname)
|
||||
bool json_include_output_property,
|
||||
uint32_t rate, uint32_t max_burst, bool buffered,
|
||||
bool time_format_iso_8601, string hostname)
|
||||
{
|
||||
// Cannot be initialized more than one time.
|
||||
if(m_initialized)
|
||||
// The engine must have been given an inspector by now.
|
||||
if(!m_inspector)
|
||||
{
|
||||
throw falco_exception("falco_outputs already initialized");
|
||||
throw falco_exception("No inspector provided");
|
||||
}
|
||||
|
||||
m_json_output = json_output;
|
||||
|
||||
// Note that falco_formats is already initialized by the engine,
|
||||
// and the following json options are not used within the engine.
|
||||
// So we can safely update them.
|
||||
falco_formats::s_json_output = json_output;
|
||||
falco_formats::s_json_include_output_property = json_include_output_property;
|
||||
falco_common::init(m_lua_main_filename.c_str(), FALCO_SOURCE_LUA_DIR);
|
||||
|
||||
m_timeout = std::chrono::milliseconds(timeout);
|
||||
// Note that falco_formats is added to both the lua state used
|
||||
// by the falco engine as well as the separate lua state used
|
||||
// by falco outputs.
|
||||
falco_formats::init(m_inspector, m_falco_engine, m_ls, json_output, json_include_output_property);
|
||||
|
||||
falco_logger::init(m_ls);
|
||||
|
||||
luaL_openlib(m_ls, "c_outputs", ll_falco_outputs, 0);
|
||||
|
||||
m_notifications_tb.init(rate, max_burst);
|
||||
|
||||
@@ -88,60 +99,43 @@ void falco_outputs::init(bool json_output,
|
||||
m_time_format_iso_8601 = time_format_iso_8601;
|
||||
m_hostname = hostname;
|
||||
|
||||
m_worker_thread = std::thread(&falco_outputs::worker, this);
|
||||
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
// This function has to be called after init() since some configuration settings
|
||||
// need to be passed to the output plugins. Then, although the worker has started,
|
||||
// the worker is still on hold, waiting for a message.
|
||||
// Thus it is still safe to call add_output() before any message has been enqueued.
|
||||
void falco_outputs::add_output(falco::outputs::config oc)
|
||||
void falco_outputs::add_output(output_config oc)
|
||||
{
|
||||
if(!m_initialized)
|
||||
uint8_t nargs = 3;
|
||||
lua_getglobal(m_ls, m_lua_add_output.c_str());
|
||||
|
||||
if(!lua_isfunction(m_ls, -1))
|
||||
{
|
||||
throw falco_exception("cannot add output: falco_outputs not initialized yet");
|
||||
throw falco_exception("No function " + m_lua_add_output + " found. ");
|
||||
}
|
||||
lua_pushstring(m_ls, oc.name.c_str());
|
||||
lua_pushnumber(m_ls, (m_buffered ? 1 : 0));
|
||||
lua_pushnumber(m_ls, (m_time_format_iso_8601 ? 1 : 0));
|
||||
|
||||
// If we have options, build up a lua table containing them
|
||||
if(oc.options.size())
|
||||
{
|
||||
nargs = 4;
|
||||
lua_createtable(m_ls, 0, oc.options.size());
|
||||
|
||||
for(auto it = oc.options.cbegin(); it != oc.options.cend(); ++it)
|
||||
{
|
||||
lua_pushstring(m_ls, (*it).second.c_str());
|
||||
lua_setfield(m_ls, -2, (*it).first.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
falco::outputs::abstract_output *oo;
|
||||
|
||||
if(oc.name == "file")
|
||||
if(lua_pcall(m_ls, nargs, 0, 0) != 0)
|
||||
{
|
||||
oo = new falco::outputs::output_file();
|
||||
const char *lerr = lua_tostring(m_ls, -1);
|
||||
throw falco_exception(string(lerr));
|
||||
}
|
||||
else if(oc.name == "program")
|
||||
{
|
||||
oo = new falco::outputs::output_program();
|
||||
}
|
||||
else if(oc.name == "stdout")
|
||||
{
|
||||
oo = new falco::outputs::output_stdout();
|
||||
}
|
||||
else if(oc.name == "syslog")
|
||||
{
|
||||
oo = new falco::outputs::output_syslog();
|
||||
}
|
||||
#ifndef MINIMAL_BUILD
|
||||
else if(oc.name == "http")
|
||||
{
|
||||
oo = new falco::outputs::output_http();
|
||||
}
|
||||
else if(oc.name == "grpc")
|
||||
{
|
||||
oo = new falco::outputs::output_grpc();
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
throw falco_exception("Output not supported: " + oc.name);
|
||||
}
|
||||
|
||||
oo->init(oc, m_buffered, m_hostname);
|
||||
m_outputs.push_back(oo);
|
||||
}
|
||||
|
||||
void falco_outputs::handle_event(gen_event *evt, string &rule, string &source,
|
||||
void falco_outputs::handle_event(gen_event *ev, string &rule, string &source,
|
||||
falco_common::priority_type priority, string &format)
|
||||
{
|
||||
if(!m_notifications_tb.claim())
|
||||
@@ -150,96 +144,70 @@ void falco_outputs::handle_event(gen_event *evt, string &rule, string &source,
|
||||
return;
|
||||
}
|
||||
|
||||
falco_outputs::ctrl_msg cmsg = {};
|
||||
cmsg.ts = evt->get_ts();
|
||||
cmsg.priority = priority;
|
||||
cmsg.source = source;
|
||||
cmsg.rule = rule;
|
||||
std::lock_guard<std::mutex> guard(m_ls_semaphore);
|
||||
lua_getglobal(m_ls, m_lua_output_event.c_str());
|
||||
|
||||
string sformat;
|
||||
if(source == "syscall")
|
||||
if(lua_isfunction(m_ls, -1))
|
||||
{
|
||||
if(m_time_format_iso_8601)
|
||||
lua_pushlightuserdata(m_ls, ev);
|
||||
lua_pushstring(m_ls, rule.c_str());
|
||||
lua_pushstring(m_ls, source.c_str());
|
||||
lua_pushstring(m_ls, falco_common::priority_names[priority].c_str());
|
||||
lua_pushnumber(m_ls, priority);
|
||||
lua_pushstring(m_ls, format.c_str());
|
||||
lua_pushstring(m_ls, m_hostname.c_str());
|
||||
|
||||
if(lua_pcall(m_ls, 7, 0, 0) != 0)
|
||||
{
|
||||
sformat = "*%evt.time.iso8601: " + falco_common::priority_names[priority];
|
||||
}
|
||||
else
|
||||
{
|
||||
sformat = "*%evt.time: " + falco_common::priority_names[priority];
|
||||
const char *lerr = lua_tostring(m_ls, -1);
|
||||
string err = "Error invoking function output: " + string(lerr);
|
||||
throw falco_exception(err);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_time_format_iso_8601)
|
||||
{
|
||||
sformat = "*%jevt.time.iso8601: " + falco_common::priority_names[priority];
|
||||
}
|
||||
else
|
||||
{
|
||||
sformat = "*%jevt.time: " + falco_common::priority_names[priority];
|
||||
}
|
||||
throw falco_exception("No function " + m_lua_output_event + " found in lua compiler module");
|
||||
}
|
||||
|
||||
// if format starts with a *, remove it, as we added our own prefix
|
||||
if(format[0] == '*')
|
||||
{
|
||||
sformat += " " + format.substr(1, format.length() - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
sformat += " " + format;
|
||||
}
|
||||
|
||||
cmsg.msg = falco_formats::format_event(evt, rule, source, falco_common::priority_names[priority], sformat);
|
||||
cmsg.fields = falco_formats::resolve_tokens(evt, source, sformat);
|
||||
|
||||
cmsg.type = ctrl_msg_type::CTRL_MSG_OUTPUT;
|
||||
m_queue.push(cmsg);
|
||||
}
|
||||
|
||||
void falco_outputs::handle_msg(uint64_t ts,
|
||||
void falco_outputs::handle_msg(uint64_t now,
|
||||
falco_common::priority_type priority,
|
||||
std::string &msg,
|
||||
std::string &rule,
|
||||
std::map<std::string, std::string> &output_fields)
|
||||
{
|
||||
falco_outputs::ctrl_msg cmsg = {};
|
||||
cmsg.ts = ts;
|
||||
cmsg.priority = priority;
|
||||
cmsg.source = "internal";
|
||||
cmsg.rule = rule;
|
||||
cmsg.fields = output_fields;
|
||||
std::string full_msg;
|
||||
|
||||
if(m_json_output)
|
||||
{
|
||||
nlohmann::json jmsg;
|
||||
|
||||
// Convert the time-as-nanoseconds to a more json-friendly ISO8601.
|
||||
time_t evttime = ts / 1000000000;
|
||||
time_t evttime = now / 1000000000;
|
||||
char time_sec[20]; // sizeof "YYYY-MM-DDTHH:MM:SS"
|
||||
char time_ns[12]; // sizeof ".sssssssssZ"
|
||||
string iso8601evttime;
|
||||
|
||||
strftime(time_sec, sizeof(time_sec), "%FT%T", gmtime(&evttime));
|
||||
snprintf(time_ns, sizeof(time_ns), ".%09luZ", ts % 1000000000);
|
||||
snprintf(time_ns, sizeof(time_ns), ".%09luZ", now % 1000000000);
|
||||
iso8601evttime = time_sec;
|
||||
iso8601evttime += time_ns;
|
||||
|
||||
jmsg["output"] = msg;
|
||||
jmsg["priority"] = falco_common::priority_names[priority];
|
||||
jmsg["priority"] = "Critical";
|
||||
jmsg["rule"] = rule;
|
||||
jmsg["time"] = iso8601evttime;
|
||||
jmsg["output_fields"] = output_fields;
|
||||
|
||||
cmsg.msg = jmsg.dump();
|
||||
full_msg = jmsg.dump();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string timestr;
|
||||
bool first = true;
|
||||
|
||||
sinsp_utils::ts_to_string(ts, ×tr, false, true);
|
||||
cmsg.msg = timestr + ": " + falco_common::priority_names[priority] + " " + msg + " (";
|
||||
sinsp_utils::ts_to_string(now, ×tr, false, true);
|
||||
full_msg = timestr + ": " + falco_common::priority_names[LOG_CRIT] + " " + msg + " (";
|
||||
for(auto &pair : output_fields)
|
||||
{
|
||||
if(first)
|
||||
@@ -248,95 +216,156 @@ void falco_outputs::handle_msg(uint64_t ts,
|
||||
}
|
||||
else
|
||||
{
|
||||
cmsg.msg += " ";
|
||||
full_msg += " ";
|
||||
}
|
||||
cmsg.msg += pair.first + "=" + pair.second;
|
||||
full_msg += pair.first + "=" + pair.second;
|
||||
}
|
||||
cmsg.msg += ")";
|
||||
full_msg += ")";
|
||||
}
|
||||
|
||||
cmsg.type = ctrl_msg_type::CTRL_MSG_OUTPUT;
|
||||
m_queue.push(cmsg);
|
||||
}
|
||||
std::lock_guard<std::mutex> guard(m_ls_semaphore);
|
||||
lua_getglobal(m_ls, m_lua_output_msg.c_str());
|
||||
if(lua_isfunction(m_ls, -1))
|
||||
{
|
||||
lua_pushstring(m_ls, full_msg.c_str());
|
||||
lua_pushstring(m_ls, falco_common::priority_names[priority].c_str());
|
||||
lua_pushnumber(m_ls, priority);
|
||||
|
||||
void falco_outputs::cleanup_outputs()
|
||||
{
|
||||
this->push(falco_outputs::ctrl_msg_type::CTRL_MSG_CLEANUP);
|
||||
if(lua_pcall(m_ls, 3, 0, 0) != 0)
|
||||
{
|
||||
const char *lerr = lua_tostring(m_ls, -1);
|
||||
string err = "Error invoking function output: " + string(lerr);
|
||||
throw falco_exception(err);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw falco_exception("No function " + m_lua_output_msg + " found in lua compiler module");
|
||||
}
|
||||
}
|
||||
|
||||
void falco_outputs::reopen_outputs()
|
||||
{
|
||||
this->push(falco_outputs::ctrl_msg_type::CTRL_MSG_REOPEN);
|
||||
}
|
||||
|
||||
void falco_outputs::stop_worker()
|
||||
{
|
||||
watchdog<void *> wd;
|
||||
wd.start([&](void *) -> void {
|
||||
falco_logger::log(LOG_NOTICE, "output channels still blocked, discarding all remaining notifications\n");
|
||||
m_queue.clear();
|
||||
this->push(falco_outputs::ctrl_msg_type::CTRL_MSG_STOP);
|
||||
});
|
||||
wd.set_timeout(m_timeout, nullptr);
|
||||
|
||||
this->push(falco_outputs::ctrl_msg_type::CTRL_MSG_STOP);
|
||||
if(m_worker_thread.joinable())
|
||||
lua_getglobal(m_ls, m_lua_output_reopen.c_str());
|
||||
if(!lua_isfunction(m_ls, -1))
|
||||
{
|
||||
m_worker_thread.join();
|
||||
throw falco_exception("No function " + m_lua_output_reopen + " found. ");
|
||||
}
|
||||
|
||||
if(lua_pcall(m_ls, 0, 0, 0) != 0)
|
||||
{
|
||||
const char *lerr = lua_tostring(m_ls, -1);
|
||||
throw falco_exception(string(lerr));
|
||||
}
|
||||
}
|
||||
|
||||
inline void falco_outputs::push(ctrl_msg_type cmt)
|
||||
int falco_outputs::handle_http(lua_State *ls)
|
||||
{
|
||||
falco_outputs::ctrl_msg cmsg = {};
|
||||
cmsg.type = cmt;
|
||||
m_queue.push(cmsg);
|
||||
}
|
||||
CURL *curl = NULL;
|
||||
CURLcode res = CURLE_FAILED_INIT;
|
||||
struct curl_slist *slist1;
|
||||
slist1 = NULL;
|
||||
|
||||
// todo(leogr,leodido): this function is not supposed to throw exceptions, and with "noexcept",
|
||||
// the program is terminated if that occurs. Although that's the wanted behavior,
|
||||
// we still need to improve the error reporting since some inner functions can throw exceptions.
|
||||
void falco_outputs::worker() noexcept
|
||||
{
|
||||
watchdog<std::string> wd;
|
||||
wd.start([&](std::string payload) -> void {
|
||||
falco_logger::log(LOG_CRIT, "\"" + payload + "\" output timeout, all output channels are blocked\n");
|
||||
});
|
||||
|
||||
auto timeout = m_timeout;
|
||||
|
||||
falco_outputs::ctrl_msg cmsg;
|
||||
do
|
||||
if(!lua_isstring(ls, -1) ||
|
||||
!lua_isstring(ls, -2))
|
||||
{
|
||||
// Block until a message becomes available.
|
||||
m_queue.pop(cmsg);
|
||||
lua_pushstring(ls, "Invalid arguments passed to handle_http()");
|
||||
lua_error(ls);
|
||||
}
|
||||
|
||||
for(const auto o : m_outputs)
|
||||
string url = (char *)lua_tostring(ls, 1);
|
||||
string msg = (char *)lua_tostring(ls, 2);
|
||||
|
||||
curl = curl_easy_init();
|
||||
if(curl)
|
||||
{
|
||||
slist1 = curl_slist_append(slist1, "Content-Type: application/json");
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, msg.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, -1L);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
if(res != CURLE_OK)
|
||||
{
|
||||
wd.set_timeout(timeout, o->get_name());
|
||||
try
|
||||
{
|
||||
switch(cmsg.type)
|
||||
{
|
||||
case ctrl_msg_type::CTRL_MSG_OUTPUT:
|
||||
o->output(&cmsg);
|
||||
break;
|
||||
case ctrl_msg_type::CTRL_MSG_CLEANUP:
|
||||
case ctrl_msg_type::CTRL_MSG_STOP:
|
||||
o->cleanup();
|
||||
break;
|
||||
case ctrl_msg_type::CTRL_MSG_REOPEN:
|
||||
o->reopen();
|
||||
break;
|
||||
default:
|
||||
falco_logger::log(LOG_DEBUG, "Outputs worker received an unknown message type\n");
|
||||
}
|
||||
}
|
||||
catch(const exception &e)
|
||||
{
|
||||
falco_logger::log(LOG_ERR, o->get_name() + ": " + string(e.what()) + "\n");
|
||||
}
|
||||
falco_logger::log(LOG_ERR, "libcurl error: " + string(curl_easy_strerror(res)));
|
||||
}
|
||||
wd.cancel_timeout();
|
||||
} while(cmsg.type != ctrl_msg_type::CTRL_MSG_STOP);
|
||||
curl_easy_cleanup(curl);
|
||||
curl = NULL;
|
||||
curl_slist_free_all(slist1);
|
||||
slist1 = NULL;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int falco_outputs::handle_grpc(lua_State *ls)
|
||||
{
|
||||
// check parameters
|
||||
if(!lua_islightuserdata(ls, -8) ||
|
||||
!lua_isstring(ls, -7) ||
|
||||
!lua_isstring(ls, -6) ||
|
||||
!lua_isstring(ls, -5) ||
|
||||
!lua_isstring(ls, -4) ||
|
||||
!lua_istable(ls, -3) ||
|
||||
!lua_isstring(ls, -2) ||
|
||||
!lua_istable(ls, -1))
|
||||
{
|
||||
lua_pushstring(ls, "Invalid arguments passed to handle_grpc()");
|
||||
lua_error(ls);
|
||||
}
|
||||
|
||||
falco::outputs::response grpc_res;
|
||||
|
||||
// time
|
||||
gen_event *evt = (gen_event *)lua_topointer(ls, 1);
|
||||
auto timestamp = grpc_res.mutable_time();
|
||||
*timestamp = google::protobuf::util::TimeUtil::NanosecondsToTimestamp(evt->get_ts());
|
||||
|
||||
// rule
|
||||
auto rule = grpc_res.mutable_rule();
|
||||
*rule = (char *)lua_tostring(ls, 2);
|
||||
|
||||
// source
|
||||
falco::schema::source s = falco::schema::source::SYSCALL;
|
||||
string sstr = (char *)lua_tostring(ls, 3);
|
||||
if(!falco::schema::source_Parse(sstr, &s))
|
||||
{
|
||||
lua_pushstring(ls, "Unknown source passed to to handle_grpc()");
|
||||
lua_error(ls);
|
||||
}
|
||||
grpc_res.set_source(s);
|
||||
|
||||
// priority
|
||||
falco::schema::priority p = falco::schema::priority::EMERGENCY;
|
||||
string pstr = (char *)lua_tostring(ls, 4);
|
||||
if(!falco::schema::priority_Parse(pstr, &p))
|
||||
{
|
||||
lua_pushstring(ls, "Unknown priority passed to to handle_grpc()");
|
||||
lua_error(ls);
|
||||
}
|
||||
grpc_res.set_priority(p);
|
||||
|
||||
// output
|
||||
auto output = grpc_res.mutable_output();
|
||||
*output = (char *)lua_tostring(ls, 5);
|
||||
|
||||
// output fields
|
||||
auto &fields = *grpc_res.mutable_output_fields();
|
||||
|
||||
lua_pushnil(ls); // so that lua_next removes it from stack and puts (k, v) on it
|
||||
while(lua_next(ls, 6) != 0)
|
||||
{
|
||||
fields[lua_tostring(ls, -2)] = lua_tostring(ls, -1);
|
||||
lua_pop(ls, 1); // remove value, keep key for lua_next
|
||||
}
|
||||
lua_pop(ls, 1); // pop table
|
||||
|
||||
// hostname
|
||||
auto host = grpc_res.mutable_hostname();
|
||||
*host = (char *)lua_tostring(ls, 7);
|
||||
|
||||
falco::outputs::queue::get().push(grpc_res);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
Copyright (C) 2019 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.
|
||||
@@ -19,52 +19,69 @@ limitations under the License.
|
||||
#include <memory>
|
||||
#include <map>
|
||||
|
||||
extern "C" {
|
||||
#include "lua.h"
|
||||
#include "lualib.h"
|
||||
#include "lauxlib.h"
|
||||
}
|
||||
|
||||
#include "gen_filter.h"
|
||||
#include "json_evt.h"
|
||||
#include "falco_common.h"
|
||||
#include "token_bucket.h"
|
||||
#include "falco_engine.h"
|
||||
#include "outputs.h"
|
||||
#include "tbb/concurrent_queue.h"
|
||||
|
||||
//
|
||||
// This class acts as the primary interface between a program and the
|
||||
// falco output engine. The falco rules engine is implemented by a
|
||||
// separate class falco_engine.
|
||||
//
|
||||
class falco_outputs
|
||||
|
||||
class falco_outputs : public falco_common
|
||||
{
|
||||
public:
|
||||
falco_outputs();
|
||||
falco_outputs(falco_engine *engine);
|
||||
virtual ~falco_outputs();
|
||||
|
||||
// The way to refer to an output (file, syslog, stdout, etc.)
|
||||
// An output has a name and set of options.
|
||||
struct output_config
|
||||
{
|
||||
std::string name;
|
||||
std::map<std::string, std::string> options;
|
||||
};
|
||||
|
||||
void init(bool json_output,
|
||||
bool json_include_output_property,
|
||||
uint32_t timeout,
|
||||
uint32_t rate, uint32_t max_burst, bool buffered,
|
||||
bool time_format_iso_8601, std::string hostname);
|
||||
|
||||
void add_output(falco::outputs::config oc);
|
||||
void add_output(output_config oc);
|
||||
|
||||
// Format then send the event to all configured outputs (`evt` is an event that has matched some rule).
|
||||
void handle_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
//
|
||||
// ev is an event that has matched some rule. Pass the event
|
||||
// to all configured outputs.
|
||||
//
|
||||
void handle_event(gen_event *ev, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format);
|
||||
|
||||
// Format then send a generic message to all outputs. Not necessarily associated with any event.
|
||||
// Send a generic message to all outputs. Not necessarily associated with any event.
|
||||
void handle_msg(uint64_t now,
|
||||
falco_common::priority_type priority,
|
||||
std::string &msg,
|
||||
std::string &rule,
|
||||
std::map<std::string, std::string> &output_fields);
|
||||
|
||||
void cleanup_outputs();
|
||||
std::map<std::string,std::string> &output_fields);
|
||||
|
||||
void reopen_outputs();
|
||||
|
||||
private:
|
||||
bool m_initialized;
|
||||
static int handle_http(lua_State *ls);
|
||||
static int handle_grpc(lua_State *ls);
|
||||
|
||||
std::vector<falco::outputs::abstract_output *> m_outputs;
|
||||
private:
|
||||
|
||||
falco_engine *m_falco_engine;
|
||||
|
||||
bool m_initialized;
|
||||
|
||||
// Rate limits notifications
|
||||
token_bucket m_notifications_tb;
|
||||
@@ -72,28 +89,12 @@ private:
|
||||
bool m_buffered;
|
||||
bool m_json_output;
|
||||
bool m_time_format_iso_8601;
|
||||
std::chrono::milliseconds m_timeout;
|
||||
std::string m_hostname;
|
||||
|
||||
enum ctrl_msg_type
|
||||
{
|
||||
CTRL_MSG_STOP = 0,
|
||||
CTRL_MSG_OUTPUT = 1,
|
||||
CTRL_MSG_CLEANUP = 2,
|
||||
CTRL_MSG_REOPEN = 3,
|
||||
};
|
||||
|
||||
struct ctrl_msg : falco::outputs::message
|
||||
{
|
||||
ctrl_msg_type type;
|
||||
};
|
||||
|
||||
typedef tbb::concurrent_bounded_queue<ctrl_msg> falco_outputs_cbq;
|
||||
|
||||
falco_outputs_cbq m_queue;
|
||||
|
||||
std::thread m_worker_thread;
|
||||
inline void push(ctrl_msg_type cmt);
|
||||
void worker() noexcept;
|
||||
void stop_worker();
|
||||
std::string m_lua_add_output = "add_output";
|
||||
std::string m_lua_output_event = "output_event";
|
||||
std::string m_lua_output_msg = "output_msg";
|
||||
std::string m_lua_output_cleanup = "output_cleanup";
|
||||
std::string m_lua_output_reopen = "output_reopen";
|
||||
std::string m_lua_main_filename = "output.lua";
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors
|
||||
Copyright (C) 2019 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.
|
||||
@@ -21,9 +21,9 @@ limitations under the License.
|
||||
|
||||
namespace falco
|
||||
{
|
||||
namespace grpc
|
||||
namespace outputs
|
||||
{
|
||||
typedef tbb::concurrent_queue<outputs::response> response_cq;
|
||||
typedef tbb::concurrent_queue<response> response_cq;
|
||||
|
||||
class queue
|
||||
{
|
||||
@@ -34,12 +34,12 @@ public:
|
||||
return instance;
|
||||
}
|
||||
|
||||
bool try_pop(outputs::response& res)
|
||||
bool try_pop(response& res)
|
||||
{
|
||||
return m_queue.try_pop(res);
|
||||
}
|
||||
|
||||
void push(outputs::response& res)
|
||||
void push(response& res)
|
||||
{
|
||||
m_queue.push(res);
|
||||
}
|
||||
@@ -56,5 +56,5 @@ public:
|
||||
queue(queue const&) = delete;
|
||||
void operator=(queue const&) = delete;
|
||||
};
|
||||
} // namespace grpc
|
||||
} // namespace output
|
||||
} // namespace falco
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors
|
||||
Copyright (C) 2019 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.
|
||||
@@ -15,9 +15,8 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
#include "config_falco.h"
|
||||
#include "falco_engine_version.h"
|
||||
#include "grpc_server_impl.h"
|
||||
#include "grpc_queue.h"
|
||||
#include "falco_outputs_queue.h"
|
||||
#include "logger.h"
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
@@ -45,7 +44,7 @@ void falco::grpc::server_impl::get(const stream_context& ctx, const outputs::req
|
||||
// m_status == stream_context::STREAMING?
|
||||
// todo(leodido) > set m_stream
|
||||
|
||||
ctx.m_has_more = queue::get().try_pop(res);
|
||||
ctx.m_has_more = outputs::queue::get().try_pop(res);
|
||||
}
|
||||
|
||||
void falco::grpc::server_impl::sub(const bidi_context& ctx, const outputs::request& req, outputs::response& res)
|
||||
@@ -62,7 +61,7 @@ void falco::grpc::server_impl::sub(const bidi_context& ctx, const outputs::reque
|
||||
// m_status == stream_context::STREAMING?
|
||||
// todo(leodido) > set m_stream
|
||||
|
||||
ctx.m_has_more = queue::get().try_pop(res);
|
||||
ctx.m_has_more = outputs::queue::get().try_pop(res);
|
||||
}
|
||||
|
||||
void falco::grpc::server_impl::version(const context& ctx, const version::request&, version::response& res)
|
||||
@@ -76,9 +75,6 @@ void falco::grpc::server_impl::version(const context& ctx, const version::reques
|
||||
auto& version = *res.mutable_version();
|
||||
version = FALCO_VERSION;
|
||||
|
||||
res.set_engine_version(FALCO_ENGINE_VERSION);
|
||||
res.set_engine_fields_checksum(FALCO_FIELDS_CHECKSUM);
|
||||
|
||||
res.set_major(FALCO_VERSION_MAJOR);
|
||||
res.set_minor(FALCO_VERSION_MINOR);
|
||||
res.set_patch(FALCO_VERSION_PATCH);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
Copyright (C) 2019 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.
|
||||
@@ -16,13 +16,25 @@ limitations under the License.
|
||||
|
||||
#include <ctime>
|
||||
#include "logger.h"
|
||||
#include "chisel_api.h"
|
||||
|
||||
#include "falco_common.h"
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
const static struct luaL_reg ll_falco [] =
|
||||
{
|
||||
{"syslog", &falco_logger::syslog},
|
||||
{NULL,NULL}
|
||||
};
|
||||
|
||||
int falco_logger::level = LOG_INFO;
|
||||
bool falco_logger::time_format_iso_8601 = false;
|
||||
|
||||
void falco_logger::init(lua_State *ls)
|
||||
{
|
||||
luaL_openlib(ls, "falco", ll_falco, 0);
|
||||
}
|
||||
|
||||
void falco_logger::set_time_format_iso_8601(bool val)
|
||||
{
|
||||
falco_logger::time_format_iso_8601 = val;
|
||||
@@ -69,6 +81,19 @@ void falco_logger::set_level(string &level)
|
||||
}
|
||||
|
||||
|
||||
int falco_logger::syslog(lua_State *ls) {
|
||||
int priority = luaL_checknumber(ls, 1);
|
||||
|
||||
if (priority > LOG_DEBUG) {
|
||||
return luaL_argerror(ls, 1, "falco.syslog: priority must be a number between 0 and 7");
|
||||
}
|
||||
|
||||
const char *msg = luaL_checkstring(ls, 2);
|
||||
::syslog(priority, "%s", msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool falco_logger::log_stderr = true;
|
||||
bool falco_logger::log_syslog = true;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
Copyright (C) 2019 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.
|
||||
@@ -19,15 +19,25 @@ limitations under the License.
|
||||
#include "sinsp.h"
|
||||
#include <syslog.h>
|
||||
|
||||
extern "C" {
|
||||
#include "lua.h"
|
||||
#include "lualib.h"
|
||||
#include "lauxlib.h"
|
||||
}
|
||||
|
||||
class falco_logger
|
||||
{
|
||||
public:
|
||||
static void init(lua_State *ls);
|
||||
|
||||
static void set_time_format_iso_8601(bool val);
|
||||
|
||||
// Will throw exception if level is unknown.
|
||||
static void set_level(string &level);
|
||||
|
||||
// value = falco.syslog(level, message)
|
||||
static int syslog(lua_State *ls);
|
||||
|
||||
static void log(int priority, const string msg);
|
||||
|
||||
static int level;
|
||||
|
||||
1
userspace/falco/lua/.gitignore
vendored
Normal file
1
userspace/falco/lua/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
lyaml*
|
||||
271
userspace/falco/lua/output.lua
Normal file
271
userspace/falco/lua/output.lua
Normal file
@@ -0,0 +1,271 @@
|
||||
-- Copyright (C) 2019 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.
|
||||
--
|
||||
|
||||
local mod = {}
|
||||
|
||||
local outputs = {}
|
||||
|
||||
function mod.stdout(event, rule, source, priority, priority_num, msg, format, hostname, options)
|
||||
mod.stdout_message(priority, priority_num, msg, options)
|
||||
end
|
||||
|
||||
function mod.stdout_message(priority, priority_num, msg, options)
|
||||
if options.buffered == 0 then
|
||||
io.stdout:setvbuf "no"
|
||||
end
|
||||
print(msg)
|
||||
end
|
||||
|
||||
function mod.stdout_cleanup()
|
||||
io.stdout:flush()
|
||||
end
|
||||
|
||||
-- Note: not actually closing/reopening stdout
|
||||
function mod.stdout_reopen(options)
|
||||
end
|
||||
|
||||
function mod.file_validate(options)
|
||||
if (not type(options.filename) == "string") then
|
||||
error("File output needs to be configured with a valid filename")
|
||||
end
|
||||
|
||||
local file, err = io.open(options.filename, "a+")
|
||||
if file == nil then
|
||||
error("Error with file output: " .. err)
|
||||
end
|
||||
file:close()
|
||||
end
|
||||
|
||||
function mod.file_open(options)
|
||||
if ffile == nil then
|
||||
ffile = io.open(options.filename, "a+")
|
||||
if options.buffered == 0 then
|
||||
ffile:setvbuf "no"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function mod.file(event, rule, source, priority, priority_num, msg, format, hostname, options)
|
||||
mod.file_message(priority, priority_num, msg, options)
|
||||
end
|
||||
|
||||
function mod.file_message(priority, priority_num, msg, options)
|
||||
if options.keep_alive == "true" then
|
||||
mod.file_open(options)
|
||||
else
|
||||
ffile = io.open(options.filename, "a+")
|
||||
end
|
||||
|
||||
ffile:write(msg, "\n")
|
||||
|
||||
if options.keep_alive == nil or options.keep_alive ~= "true" then
|
||||
ffile:close()
|
||||
ffile = nil
|
||||
end
|
||||
end
|
||||
|
||||
function mod.file_cleanup()
|
||||
if ffile ~= nil then
|
||||
ffile:flush()
|
||||
ffile:close()
|
||||
ffile = nil
|
||||
end
|
||||
end
|
||||
|
||||
function mod.file_reopen(options)
|
||||
if options.keep_alive == "true" then
|
||||
mod.file_cleanup()
|
||||
mod.file_open(options)
|
||||
end
|
||||
end
|
||||
|
||||
function mod.syslog(event, rule, source, priority, priority_num, msg, format, hostname, options)
|
||||
mod.syslog_message(priority, priority_num, msg, options)
|
||||
end
|
||||
|
||||
function mod.syslog_message(priority, priority_num, msg, options)
|
||||
falco.syslog(priority_num, msg)
|
||||
end
|
||||
|
||||
function mod.syslog_cleanup()
|
||||
end
|
||||
|
||||
function mod.syslog_reopen()
|
||||
end
|
||||
|
||||
function mod.program_open(options)
|
||||
if pfile == nil then
|
||||
pfile = io.popen(options.program, "w")
|
||||
if options.buffered == 0 then
|
||||
pfile:setvbuf "no"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function mod.program(event, rule, source, priority, priority_num, msg, format, hostname, options)
|
||||
mod.program_message(priority, priority_num, msg, options)
|
||||
end
|
||||
|
||||
function mod.program_message(priority, priority_num, msg, options)
|
||||
-- XXX Ideally we'd check that the program ran
|
||||
-- successfully. However, the luajit we're using returns true even
|
||||
-- when the shell can't run the program.
|
||||
|
||||
-- Note: options are all strings
|
||||
if options.keep_alive == "true" then
|
||||
mod.program_open(options)
|
||||
else
|
||||
pfile = io.popen(options.program, "w")
|
||||
end
|
||||
|
||||
pfile:write(msg, "\n")
|
||||
|
||||
if options.keep_alive == nil or options.keep_alive ~= "true" then
|
||||
pfile:close()
|
||||
pfile = nil
|
||||
end
|
||||
end
|
||||
|
||||
function mod.program_cleanup()
|
||||
if pfile ~= nil then
|
||||
pfile:flush()
|
||||
pfile:close()
|
||||
pfile = nil
|
||||
end
|
||||
end
|
||||
|
||||
function mod.program_reopen(options)
|
||||
if options.keep_alive == "true" then
|
||||
mod.program_cleanup()
|
||||
mod.program_open(options)
|
||||
end
|
||||
end
|
||||
|
||||
function mod.http(event, rule, source, priority, priority_num, msg, format, hostname, options)
|
||||
mod.http_message(priority, priority_num, msg, options)
|
||||
end
|
||||
|
||||
function mod.http_message(priority, priority_num, msg, options)
|
||||
c_outputs.handle_http(options.url, msg)
|
||||
end
|
||||
|
||||
function mod.http_cleanup()
|
||||
end
|
||||
|
||||
function mod.http_reopen()
|
||||
end
|
||||
|
||||
function mod.grpc(event, rule, source, priority, priority_num, msg, format, hostname, options)
|
||||
fields = formats.resolve_tokens(event, source, format)
|
||||
c_outputs.handle_grpc(event, rule, source, priority, msg, fields, hostname, options)
|
||||
end
|
||||
|
||||
function mod.grpc_message(priority, priority_num, msg, options)
|
||||
-- todo(fntlnz, leodido) > gRPC does not support subscribing to dropped events yet
|
||||
end
|
||||
|
||||
|
||||
function mod.grpc_cleanup()
|
||||
end
|
||||
|
||||
function mod.grpc_reopen()
|
||||
end
|
||||
|
||||
function output_event(event, rule, source, priority, priority_num, format, hostname)
|
||||
-- If format starts with a *, remove it, as we're adding our own
|
||||
-- prefix here.
|
||||
if format:sub(1, 1) == "*" then
|
||||
format = format:sub(2)
|
||||
end
|
||||
|
||||
-- time_format_iso_8601 will be the same for all output channels
|
||||
time_format_iso_8601 = 0
|
||||
|
||||
for index, o in ipairs(outputs) do
|
||||
time_format_iso_8601 = o.options.time_format_iso_8601
|
||||
break
|
||||
end
|
||||
|
||||
if source == "syscall" then
|
||||
if time_format_iso_8601 == 1 then
|
||||
format = "*%evt.time.iso8601: " .. priority .. " " .. format
|
||||
else
|
||||
format = "*%evt.time: " .. priority .. " " .. format
|
||||
end
|
||||
else
|
||||
if time_format_iso_8601 == 1 then
|
||||
format = "*%jevt.time.iso8601: " .. priority .. " " .. format
|
||||
else
|
||||
format = "*%jevt.time: " .. priority .. " " .. format
|
||||
end
|
||||
end
|
||||
|
||||
msg = formats.format_event(event, rule, source, priority, format)
|
||||
|
||||
for index, o in ipairs(outputs) do
|
||||
o.output(event, rule, source, priority, priority_num, msg, format, hostname, o.options)
|
||||
end
|
||||
end
|
||||
|
||||
function output_msg(msg, priority, priority_num)
|
||||
for index, o in ipairs(outputs) do
|
||||
o.message(priority, priority_num, msg, o.options)
|
||||
end
|
||||
end
|
||||
|
||||
function output_cleanup()
|
||||
formats.free_formatters()
|
||||
for index, o in ipairs(outputs) do
|
||||
o.cleanup()
|
||||
end
|
||||
end
|
||||
|
||||
function output_reopen()
|
||||
for index, o in ipairs(outputs) do
|
||||
o.reopen(o.options)
|
||||
end
|
||||
end
|
||||
|
||||
function add_output(output_name, buffered, time_format_iso_8601, options)
|
||||
if not (type(mod[output_name]) == "function") then
|
||||
error("rule_loader.add_output(): invalid output_name: " .. output_name)
|
||||
end
|
||||
|
||||
-- outputs can optionally define a validation function so that we don't
|
||||
-- find out at runtime (when an event finally matches a rule!) that the options are invalid
|
||||
if (type(mod[output_name .. "_validate"]) == "function") then
|
||||
mod[output_name .. "_validate"](options)
|
||||
end
|
||||
|
||||
if options == nil then
|
||||
options = {}
|
||||
end
|
||||
|
||||
options.buffered = buffered
|
||||
options.time_format_iso_8601 = time_format_iso_8601
|
||||
|
||||
table.insert(
|
||||
outputs,
|
||||
{
|
||||
output = mod[output_name],
|
||||
cleanup = mod[output_name .. "_cleanup"],
|
||||
reopen = mod[output_name .. "_reopen"],
|
||||
message = mod[output_name .. "_message"],
|
||||
options = options
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
return mod
|
||||
44
userspace/falco/lua/test.lua
Normal file
44
userspace/falco/lua/test.lua
Normal file
@@ -0,0 +1,44 @@
|
||||
-- Copyright (C) 2019 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.
|
||||
--
|
||||
|
||||
local parser = require "parser"
|
||||
|
||||
if #arg ~= 1 then
|
||||
print("Usage: test.lua <string>")
|
||||
os.exit(1)
|
||||
end
|
||||
|
||||
local macros = {}
|
||||
local ast
|
||||
|
||||
local function doit(line)
|
||||
ast = parser.parse_filter(line)
|
||||
|
||||
if not ast then
|
||||
print("error", error_msg)
|
||||
os.exit(1)
|
||||
end
|
||||
|
||||
end
|
||||
for str in string.gmatch(arg[1], "([^;]+)") do
|
||||
doit(str)
|
||||
end
|
||||
|
||||
if (ast and ast.type) then
|
||||
parser.print_ast(ast)
|
||||
end
|
||||
|
||||
os.exit(0)
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "falco_common.h"
|
||||
#include "gen_filter.h"
|
||||
|
||||
namespace falco
|
||||
{
|
||||
namespace outputs
|
||||
{
|
||||
|
||||
//
|
||||
// The way to refer to an output (file, syslog, stdout, etc.)
|
||||
// An output has a name and set of options.
|
||||
//
|
||||
struct config
|
||||
{
|
||||
std::string name;
|
||||
std::map<std::string, std::string> options;
|
||||
};
|
||||
|
||||
//
|
||||
// The message to be outputted. It can either refer to:
|
||||
// - an event that has matched some rule,
|
||||
// - or a generic message (e.g., a drop alert).
|
||||
//
|
||||
struct message
|
||||
{
|
||||
uint64_t ts;
|
||||
falco_common::priority_type priority;
|
||||
std::string msg;
|
||||
std::string rule;
|
||||
std::string source;
|
||||
map<std::string, std::string> fields;
|
||||
};
|
||||
|
||||
//
|
||||
// This class acts as the primary interface for implementing
|
||||
// a Falco output class.
|
||||
//
|
||||
|
||||
class abstract_output
|
||||
{
|
||||
public:
|
||||
virtual ~abstract_output() {}
|
||||
|
||||
void init(config oc, bool buffered, std::string hostname)
|
||||
{
|
||||
m_oc = oc;
|
||||
m_buffered = buffered;
|
||||
m_hostname = hostname;
|
||||
}
|
||||
|
||||
// Return the output's name as per its configuration.
|
||||
const std::string get_name() const
|
||||
{
|
||||
return m_oc.name;
|
||||
}
|
||||
|
||||
// Output a message.
|
||||
virtual void output(const message *msg) = 0;
|
||||
|
||||
// Possibly close the output and open it again.
|
||||
virtual void reopen() {}
|
||||
|
||||
// Possibly flush the output.
|
||||
virtual void cleanup() {}
|
||||
|
||||
protected:
|
||||
config m_oc;
|
||||
bool m_buffered;
|
||||
std::string m_hostname;
|
||||
};
|
||||
|
||||
} // namespace outputs
|
||||
} // namespace falco
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
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 "outputs_file.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
void falco::outputs::output_file::open_file()
|
||||
{
|
||||
if(!m_buffered)
|
||||
{
|
||||
m_outfile.rdbuf()->pubsetbuf(0, 0);
|
||||
}
|
||||
if(!m_outfile.is_open())
|
||||
{
|
||||
m_outfile.open(m_oc.options["filename"], fstream::app);
|
||||
}
|
||||
}
|
||||
|
||||
void falco::outputs::output_file::output(const message *msg)
|
||||
{
|
||||
open_file();
|
||||
m_outfile << msg->msg + "\n";
|
||||
|
||||
if(m_oc.options["keep_alive"] != "true")
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
void falco::outputs::output_file::cleanup()
|
||||
{
|
||||
if(m_outfile.is_open())
|
||||
{
|
||||
m_outfile.close();
|
||||
}
|
||||
}
|
||||
|
||||
void falco::outputs::output_file::reopen()
|
||||
{
|
||||
cleanup();
|
||||
open_file();
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "outputs.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
namespace falco
|
||||
{
|
||||
namespace outputs
|
||||
{
|
||||
|
||||
class output_file : public abstract_output
|
||||
{
|
||||
void output(const message *msg);
|
||||
|
||||
void cleanup();
|
||||
|
||||
void reopen();
|
||||
|
||||
private:
|
||||
void open_file();
|
||||
|
||||
std::ofstream m_outfile;
|
||||
};
|
||||
|
||||
} // namespace outputs
|
||||
} // namespace falco
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
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 <google/protobuf/util/time_util.h>
|
||||
#include "outputs_grpc.h"
|
||||
#include "grpc_queue.h"
|
||||
#include "falco_common.h"
|
||||
#include "formats.h"
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
void falco::outputs::output_grpc::output(const message *msg)
|
||||
{
|
||||
falco::outputs::response grpc_res;
|
||||
|
||||
// time
|
||||
auto timestamp = grpc_res.mutable_time();
|
||||
*timestamp = google::protobuf::util::TimeUtil::NanosecondsToTimestamp(msg->ts);
|
||||
|
||||
// rule
|
||||
auto r = grpc_res.mutable_rule();
|
||||
*r = msg->rule;
|
||||
|
||||
// source
|
||||
falco::schema::source s = falco::schema::source::SYSCALL;
|
||||
if(!falco::schema::source_Parse(msg->source, &s))
|
||||
{
|
||||
throw falco_exception("Unknown source passed to output_grpc::output()");
|
||||
}
|
||||
grpc_res.set_source(s);
|
||||
|
||||
// priority
|
||||
falco::schema::priority p = falco::schema::priority::EMERGENCY;
|
||||
if(!falco::schema::priority_Parse(falco_common::priority_names[msg->priority], &p))
|
||||
{
|
||||
throw falco_exception("Unknown priority passed to output_grpc::output()");
|
||||
}
|
||||
grpc_res.set_priority(p);
|
||||
|
||||
// output
|
||||
auto output = grpc_res.mutable_output();
|
||||
*output = msg->msg;
|
||||
|
||||
// output fields
|
||||
auto &fields = *grpc_res.mutable_output_fields();
|
||||
for(const auto &kv : msg->fields)
|
||||
{
|
||||
fields[kv.first] = kv.second;
|
||||
}
|
||||
|
||||
// hostname
|
||||
auto host = grpc_res.mutable_hostname();
|
||||
*host = m_hostname;
|
||||
|
||||
falco::grpc::queue::get().push(grpc_res);
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "outputs.h"
|
||||
|
||||
namespace falco
|
||||
{
|
||||
namespace outputs
|
||||
{
|
||||
|
||||
class output_grpc : public abstract_output
|
||||
{
|
||||
void output(const message *msg);
|
||||
};
|
||||
|
||||
} // namespace outputs
|
||||
} // namespace falco
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
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 "outputs_http.h"
|
||||
#include "logger.h"
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
void falco::outputs::output_http::output(const message *msg)
|
||||
{
|
||||
CURL *curl = NULL;
|
||||
CURLcode res = CURLE_FAILED_INIT;
|
||||
struct curl_slist *slist1;
|
||||
slist1 = NULL;
|
||||
|
||||
curl = curl_easy_init();
|
||||
if(curl)
|
||||
{
|
||||
slist1 = curl_slist_append(slist1, "Content-Type: application/json");
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, m_oc.options["url"].c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, msg->msg.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, -1L);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
if(res != CURLE_OK)
|
||||
{
|
||||
falco_logger::log(LOG_ERR, "libcurl error: " + string(curl_easy_strerror(res)));
|
||||
}
|
||||
curl_easy_cleanup(curl);
|
||||
curl = NULL;
|
||||
curl_slist_free_all(slist1);
|
||||
slist1 = NULL;
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "outputs.h"
|
||||
|
||||
namespace falco
|
||||
{
|
||||
namespace outputs
|
||||
{
|
||||
|
||||
class output_http : public abstract_output
|
||||
{
|
||||
void output(const message *msg);
|
||||
};
|
||||
|
||||
} // namespace outputs
|
||||
} // namespace falco
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
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 "outputs_program.h"
|
||||
#include <stdio.h>
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
void falco::outputs::output_program::open_pfile()
|
||||
{
|
||||
if(m_pfile == nullptr)
|
||||
{
|
||||
m_pfile = popen(m_oc.options["program"].c_str(), "w");
|
||||
|
||||
if(!m_buffered)
|
||||
{
|
||||
setvbuf(m_pfile, NULL, _IONBF, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void falco::outputs::output_program::output(const message *msg)
|
||||
{
|
||||
open_pfile();
|
||||
|
||||
fprintf(m_pfile, "%s\n", msg->msg.c_str());
|
||||
|
||||
if(m_oc.options["keep_alive"] != "true")
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
void falco::outputs::output_program::cleanup()
|
||||
{
|
||||
if(m_pfile != nullptr)
|
||||
{
|
||||
pclose(m_pfile);
|
||||
m_pfile = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void falco::outputs::output_program::reopen()
|
||||
{
|
||||
cleanup();
|
||||
open_pfile();
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "outputs.h"
|
||||
|
||||
namespace falco
|
||||
{
|
||||
namespace outputs
|
||||
{
|
||||
|
||||
class output_program : public abstract_output
|
||||
{
|
||||
void output(const message *msg);
|
||||
|
||||
void cleanup();
|
||||
|
||||
void reopen();
|
||||
|
||||
private:
|
||||
void open_pfile();
|
||||
|
||||
FILE *m_pfile;
|
||||
};
|
||||
|
||||
} // namespace outputs
|
||||
} // namespace falco
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
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 "outputs_stdout.h"
|
||||
#include <iostream>
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
void falco::outputs::output_stdout::output(const message *msg)
|
||||
{
|
||||
//
|
||||
// By default, the stdout stream is fully buffered or line buffered
|
||||
// (if the stream can be determined to refer to an interactive device, e.g. in a TTY).
|
||||
// Just enable automatic flushing when unbuffered output is desired.
|
||||
// Note that it is set every time since other writings to the stdout can disable it.
|
||||
//
|
||||
if(!m_buffered)
|
||||
{
|
||||
std::cout << std::unitbuf;
|
||||
}
|
||||
std::cout << msg->msg + "\n";
|
||||
}
|
||||
|
||||
void falco::outputs::output_stdout::cleanup()
|
||||
{
|
||||
std::cout.flush();
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "outputs.h"
|
||||
|
||||
namespace falco
|
||||
{
|
||||
namespace outputs
|
||||
{
|
||||
|
||||
class output_stdout : public abstract_output
|
||||
{
|
||||
void output(const message *msg);
|
||||
|
||||
void cleanup();
|
||||
};
|
||||
|
||||
} // namespace outputs
|
||||
} // namespace falco
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
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 "outputs_syslog.h"
|
||||
#include <syslog.h>
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
void falco::outputs::output_syslog::output(const message *msg)
|
||||
{
|
||||
// Syslog output should not have any trailing newline
|
||||
::syslog(msg->priority, "%s", msg->msg.c_str());
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "outputs.h"
|
||||
|
||||
namespace falco
|
||||
{
|
||||
namespace outputs
|
||||
{
|
||||
|
||||
class output_syslog : public abstract_output
|
||||
{
|
||||
void output(const message *msg);
|
||||
};
|
||||
|
||||
} // namespace outputs
|
||||
} // namespace falco
|
||||
@@ -57,7 +57,4 @@ enum source {
|
||||
k8s_audit = 1;
|
||||
K8s_audit = 1;
|
||||
K8S_audit = 1;
|
||||
INTERNAL = 2;
|
||||
internal = 2;
|
||||
Internal = 2;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
#!/bin/env/bash
|
||||
#!/bin/sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SOURCE_DIR=$1
|
||||
OPENSSL=$2
|
||||
|
||||
NEW_CHECKSUM=$(./falco --list -N | sha256sum | awk '{print $1}')
|
||||
if ! command -v "${OPENSSL}" version > /dev/null 2>&1; then
|
||||
echo "No openssl command at ${OPENSSL}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
NEW_CHECKSUM=$(./falco --list -N | ${OPENSSL} dgst -sha256 | awk '{print $2}')
|
||||
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
|
||||
echo "Set of fields supported has changed (new checksum $NEW_CHECKSUM != old checksum $CUR_CHECKSUM)."
|
||||
echo "Update checksum and/or version in falco_engine_version.h."
|
||||
|
||||
@@ -36,14 +36,10 @@ message request
|
||||
// its parts as per semver 2.0 specification (https://semver.org).
|
||||
message response
|
||||
{
|
||||
// falco version
|
||||
string version = 1;
|
||||
uint32 major = 2;
|
||||
uint32 minor = 3;
|
||||
uint32 patch = 4;
|
||||
string prerelease = 5;
|
||||
string build = 6;
|
||||
// falco engine version
|
||||
uint32 engine_version = 7;
|
||||
string engine_fields_checksum = 8;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user