Compare commits

...

51 Commits

Author SHA1 Message Date
Leonardo Grasso
359bd41b2e chore(userspace/falco): correct comment
Co-authored-by: Andrea Terzolo <andrea.terzolo@polito.it>
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-08-09 13:15:43 +02:00
Leonardo Grasso
27fb674406 chore: cleanup Mesos references
Co-authored-by: Andrea Terzolo <andrea.terzolo@polito.it>
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-08-09 11:18:36 +02:00
Leonardo Grasso
4b35d71c99 chore(userspace/falco): remove unused mesos_api var
Co-authored-by: Andrea Terzolo <andrea.terzolo@polito.it>
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-08-09 11:15:35 +02:00
Leonardo Grasso
710d15a2fd chore(userspace/falco/app_actions): remove Mesos support
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-08-09 11:13:27 +02:00
Leonardo Grasso
3a445c6457 update!: remove --mesos-api and -pm command-line flags
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2022-08-09 11:12:30 +02:00
Melissa Kilby
0ab66c6fb5 update(userspace/falco): rename some buffer kernel side event drop metrics, add comments
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2022-08-08 10:28:42 +02:00
Melissa Kilby
1588f37788 update(userspace/falco): extend buffer kernel side event drop metrics
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2022-08-08 10:28:42 +02:00
incertum
66af8ad52b new(userspace/falco): extend ebpf buffer kernel side event drop metrics
Signed-off-by: incertum <melissa.kilby.oss@gmail.com>
2022-08-08 10:28:42 +02:00
Andrea Terzolo
ff247f922d chore(test/utils): remove unused script
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-08-05 17:56:28 +02:00
Melissa Kilby
e9ba5d751f cleanup(rules): cleanup rules disabled by default
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2022-08-05 14:50:28 +02:00
Andrea Terzolo
c81f3fc87e docs(falco-driver-loader): add some comments in falco-driver-loader
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-08-05 11:36:28 +02:00
Mark Stemm
a37e2252b2 Update tests to use result struct + json-based validation
Update tests that validated rules files (typically looking for
errors/warnings) to use the new result struct + json based validation:

- When validating rules files, always use json output.

- In test cases, instead of parsing stderr/stdout, use new test
  properties "validate_ok", "validate_errors",
  "validate_warnings". These parse the json output and look for
  specific tuples of (error code, error message, item type, item name)
  in the output.

- There were a few tests that were actually validation tests but using
  the -r argument to load rules. Convert them to validation tests. In
  one case, split the test into two separate tests--one for
  validation, one ensuring that the rule doesn't match anything.

- There were a couple of tests that were duplicates of existing
  validation tests, just checking for the error in a different
  way. Remove them.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2022-08-04 14:49:23 +02:00
Mark Stemm
550cdbd176 Falco application changes to support rule loading result struct
Update the load_rules_files and validate_rules_files actions to use
the new falco_engine methods that return a rules result struct. The
app action interface is the same, returning ::fatal on error,
ok()/exit() otherwise. The difference is how any warnings/errors are
obtained--from the struct instead of an exception.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2022-08-04 14:49:23 +02:00
Mark Stemm
f7f6d72ac0 Rule loader changes to support result objects
Changes to the rule loader to support result objects:

- Instead of throwing falco_exception on internal error, throw a
  rule_load_exception instead, which contains distinct
  error/message/context information.

- A context object contains a chain of location structs chaining from
  the document root to the object where the error occurred. Each
  location has a file position (as a YAML::Mark), an item
  type (e.g. "rule", "list", "exception"), and an item name (e.g. "Write
  Below Etc"). This will allow showing the exact location of an
  error (e.g. list item/exception field) while also remembering the item
  that contained it.

- All the _info structs now contain a context so errors that occur
  after yaml parsing can still point to the original location in the
  yaml file.

- rule_loader::result is an implementation of the abstract class
  defined in falco_load_result. The implementation keeps track of a
  list of errors/warnigns that used to be in the configuration object,

- Clean up compile_ methods to just throw rule_load_exceptions or
  return nothing, and ensure that all rule_load_exceptions are caught in
  compile(). When caught, errors are added to the result object.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2022-08-04 14:49:23 +02:00
Mark Stemm
cbe7cceb87 Modify rule reader to use a result struct
Modify rule reader to use a result struct for errors and warnings:

- Instead of throwing a falco_exception to pass back errors, use a
  rule_load_exception, which contains distinct error codes, messages,
  and a context that points to the location of the error.

- The static method context_yaml_get_context() has moved to a method
  of the rule_loader context object + the result as_string() method.

- As objects are parsed, create relevant context objects as reading
  drills down into the contents of a rule/list/exception. This will
  enable for specific errors in, say, the middle of an exception/list
  while remembering the object that contains it.

- Modify decode_val()/decode_seq() to always return errors as
  exceptions. Previously, it was a mix of a bool return + some
  exceptions.

- decode_val()/decode_seq() are now more consistent about returning
  distinct errors for the property not existing, the property existing
  but not being a scalar/sequence value, and not being convertable to
  the templated value.

- Combine the two nearly identical decode_seq() functions into a
  single one that uses a lambda to perform the final step of adding to
  the vector/set.

- There are some item-specific decode_xxx functions for specific
  item properties like tags, exceptions fields/comps/values, etc.
  that call the above functions.

These changes simplify the calls to decode_seq()/decode_val() as they
don't need to add their own errors when returning false. Also some
calls weren't checking the return value.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2022-08-04 14:49:23 +02:00
Mark Stemm
bb44d992ab Change filter_warning_resolver to use warning codes
Now that we have a result struct and set of warning codes, change the
filter_warning_resolver to use them. This involves populating a set of
warning codes instead of strings.

Also, the methods to format warnings into human-readable strings is
now in the falco_load_result static methods, so move the text there
and remove the methods here.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2022-08-04 14:49:23 +02:00
Mark Stemm
0066ba49ea Falco engine changes to support load_rules result class
Add new load_rules methods that return a result object instead of
throwing exceptions on error. The existing load_rules methods call the
new methods internally and continue to throw exceptions on
error/return individual values on success.

The result is returned as a unique_ptr so it can be populated while
loading rules (as a part of the configuration object) and then move()d
to the return value.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2022-08-04 14:49:23 +02:00
Mark Stemm
8497f25a43 Add a load result interface for use in new load_rules methods
Define a falco_load_result abstract class for use in new load_rules
methods. It's abstract so the implementation details in
rule_loader/rule_reader can be hidden from someone who wants to use
the API to load rules and work with a result.

The class defines a set of error codes/warning codes and has static
methods to get a short and long description of each error/warning.

There are virtual methods to access the important parts of a result:
 - successful or not
 - a string representation of the result, suitable for display to
   users. Takes a verbose argument. When verbose is true, the string is
   multi-line and has full details, including locations, item names,
   etc. When verbose is false, the string is single-line and just
   returns error codes.
 - a json representation of the result, suitable for automated
   parsing/interpretation later.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2022-08-04 14:49:23 +02:00
Andrea Terzolo
6b7be38e41 test: update a comment
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-08-04 11:47:22 +02:00
Andrea Terzolo
9d443685ea new(userspace): support SCAP_FILTERED_EVENT return code
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-08-04 11:47:22 +02:00
Jason Dellaluce
928d3225b9 fix(cmake): force using bundled valijson
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2022-08-03 15:58:21 +02:00
Jason Dellaluce
a531e8b3ed fix(test): use old event versions in trace tests
Co-authored-by: Andrea Terzolo <andrea.terzolo@polito.it>
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2022-08-03 15:58:21 +02:00
Jason Dellaluce
07fde46e7c fix(test): sync plugin tests to new plugin loader errors
Co-authored-by: Andrea Terzolo <andrea.terzolo@polito.it>
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2022-08-03 15:58:21 +02:00
Jason Dellaluce
136b528849 fix(tests): index old version of events in rulesets
Co-authored-by: Andrea Terzolo <andrea.terzolo@polito.it>
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2022-08-03 15:58:21 +02:00
Jason Dellaluce
a46cbcffe8 fix(engine): index old version of events in rulesets
Co-authored-by: Andrea Terzolo <andrea.terzolo@polito.it>
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2022-08-03 15:58:21 +02:00
Jason Dellaluce
577ba5904b update(engine): bump version to 14 and update fields checksum
Co-authored-by: Andrea Terzolo <andrea.terzolo@polito.it>
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2022-08-03 15:58:21 +02:00
Jason Dellaluce
1b8c8a86ec update(cmake): bump libs version to b4c198773bf05486e122f6d3f7f63be125242413
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2022-08-03 15:58:21 +02:00
Jason Dellaluce
7317d80dd8 update(cmake): bump driver version to b4c198773bf05486e122f6d3f7f63be125242413
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2022-08-03 15:58:21 +02:00
Andrea Terzolo
c8bc5758c3 new(userspace): print architecture information
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-07-31 19:57:29 +02:00
Federico Di Pierro
ae43f30b0d fix(ci): fixed docker manifest circleci.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2022-07-29 12:29:02 +02:00
Federico Di Pierro
fb579615a3 cleanup(ci): natively builds docker images for x86_64 and arm64 and then use docker manifest to combine them.
This allows for native-speed build of docker images, reducing CI time spent in
docker buildx qemu cross build for arm64 up to 10x.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2022-07-29 10:11:02 +02:00
Andrea Terzolo
b759e77fda new(userspace): print if the BPF probe is enabled
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-07-28 12:25:57 +02:00
Andrea Terzolo
74b6186f7d new(userspace): print enabled sources when falco starts
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-07-28 12:25:57 +02:00
Mark Stemm
baf5540c30 Remove required_engine_version from falco engine load_rules APIs
The only use of it was to include in --support output, which is
redundant as the support output already includes the full contents of
each rules file.

Additionally, it wasn't even being updated after the switch from lua
rules loading to c++ rules
loading (https://github.com/falcosecurity/falco/pull/1966/ or
surrounding PRs).

This will simplify follow-on changes to add a real "result" to rules
loading methods, as there will be fewer API variants to support.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2022-07-25 17:57:42 +02:00
Eric Engberg
c3ddd7d5f1 fix: added arch to bpf download url
Signed-off-by: Eric Engberg <eric.engberg@hardrockdigital.com>
2022-07-22 11:06:07 +02:00
Stefano
b378c3a77d Add darryk10 as rules OWNERS as reviewer
Signed-off-by: darryk10 <stefano.chierici@sysdig.com>
2022-07-21 17:42:07 +02:00
Jason Dellaluce
0cab9ba6ed chore(OWNERS): remove duplicates in reviewers
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2022-07-20 10:39:56 +02:00
Jason Dellaluce
8cb6fc532f cleanup(OWNERS): remove inactive approvers
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2022-07-20 10:39:56 +02:00
Andrea Terzolo
35db0b4a24 cleanup(userspace): remove unused logic
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-07-14 09:58:50 +02:00
Andrea Terzolo
4136a27de1 new(userspace): add exception management
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-07-14 09:58:50 +02:00
Andrea Terzolo
e73dbd4b42 new(userspace): add current drop_pct
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
Co-authored-by: Shane Lawrence <shane@lawrence.dev>
2022-07-14 09:58:50 +02:00
Andrea Terzolo
b57a2d5a5f update(userspace): introduce nlohmann json library
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-07-14 09:58:50 +02:00
Federico Di Pierro
1bf5f864bc chore(docs): updated release.md template for packages adding aarch64 packages.
Moreover, updated readme using aarch64 instead of arm64 (same that is used in the badge), and adding "-x86_64" suffix to x86 packages.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2022-07-13 12:01:23 +02:00
Alessandro Brucato
c40d1a5141 Update rules/falco_rules.yaml
Signed-off-by: Alessandro Brucato <alessandro.brucato@sysdig.com>
2022-07-13 11:54:23 +02:00
Alessandro Brucato
409ca4382e Update rules/falco_rules.yaml
Signed-off-by: Alessandro Brucato <alessandro.brucato@sysdig.com>

Co-authored-by: schie <77834235+darryk10@users.noreply.github.com>
2022-07-13 11:54:23 +02:00
Alessandro Brucato
a71a635b7e Update rules/falco_rules.yaml
Signed-off-by: Alessandro Brucato <alessandro.brucato@sysdig.com>

Co-authored-by: schie <77834235+darryk10@users.noreply.github.com>
2022-07-13 11:54:23 +02:00
Alessandro Brucato
07024a2e0f Update rules/falco_rules.yaml
Signed-off-by: Alessandro Brucato <alessandro.brucato@sysdig.com>

Co-authored-by: schie <77834235+darryk10@users.noreply.github.com>
2022-07-13 11:54:23 +02:00
Brucedh
6feeaee0cd Added exception to Launch Privileged Container
Signed-off-by: Alessandro Brucato <alessandro.brucato@sysdig.com>
2022-07-13 11:54:23 +02:00
Andrea Terzolo
a7153f2fd8 fix(userspace): compute the drop ratio in the right way
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
Co-authored-by: Shane Lawrence <shane@lawrence.dev>
2022-07-13 09:38:22 +02:00
Ravi Ranjan
c078f7c21d Falco Rules/Conditions Updates
Signed-off-by: Ravi Ranjan <ravi.ranjan@elastisys.com>
2022-07-12 12:08:38 +02:00
Aldo Lacuku
46f625c449 chore(engine): remove trailing colon from logs when loading rule files
Signed-off-by: Aldo Lacuku <aldo@lacuku.eu>
2022-07-12 10:40:43 +02:00
49 changed files with 2389 additions and 1246 deletions

View File

@@ -1,4 +1,2 @@
approvers:
- jonahjon
reviewers:
emeritus_approvers:
- jonahjon

View File

@@ -316,56 +316,169 @@ jobs:
FALCO_VERSION=$(cat /build/release/userspace/falco/config_falco.h | grep 'FALCO_VERSION ' | cut -d' ' -f3 | sed -e 's/^"//' -e 's/"$//')
/source/falco/scripts/publish-deb -f /build/release/falco-${FALCO_VERSION}-x86_64.deb -f /build-arm64/release/falco-${FALCO_VERSION}-aarch64.deb -r deb-dev
"build-docker-dev":
docker:
- image: alpine:3.16
steps:
- attach_workspace:
at: /
- setup_remote_docker:
version: 20.10.12
docker_layer_caching: true
- run:
name: Install deps
command: |
apk update
apk add make bash git docker docker-cli-buildx py3-pip
pip install awscli
- run:
name: Login to registries
command: |
echo ${DOCKERHUB_SECRET} | docker login -u ${DOCKERHUB_USER} --password-stdin
aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws/falcosecurity
- run:
name: Build and publish no-driver-dev
command: |
FALCO_VERSION=$(cat /build/release/userspace/falco/config_falco.h | grep 'FALCO_VERSION ' | cut -d' ' -f3 | sed -e 's/^"//' -e 's/"$//')
cd /source/falco
docker buildx build --push --build-arg VERSION_BUCKET=bin-dev --build-arg FALCO_VERSION=${FALCO_VERSION} \
-t falcosecurity/falco-no-driver:x86_64-master \
-t falcosecurity/falco:x86_64-master-slim \
-t public.ecr.aws/falcosecurity/falco-no-driver:x86_64-master \
-t public.ecr.aws/falcosecurity/falco:x86_64-master-slim \
docker/no-driver
- run:
name: Build and publish falco-dev
command: |
FALCO_VERSION=$(cat /build/release/userspace/falco/config_falco.h | grep 'FALCO_VERSION ' | cut -d' ' -f3 | sed -e 's/^"//' -e 's/"$//')
cd /source/falco
docker buildx build --push --build-arg VERSION_BUCKET=deb-dev --build-arg FALCO_VERSION=${FALCO_VERSION} \
-t falcosecurity/falco:x86_64-master \
-t public.ecr.aws/falcosecurity/falco:x86_64-master \
docker/falco
- run:
name: Build and publish falco-driver-loader-dev
command: |
cd /source/falco
docker buildx build --push --build-arg FALCO_IMAGE_TAG=master \
-t falcosecurity/falco-driver-loader:x86_64-master \
-t public.ecr.aws/falcosecurity/falco-driver-loader:x86_64-master \
docker/driver-loader
"build-docker-dev-arm64":
machine:
enabled: true
image: ubuntu-2004:202101-01
docker_layer_caching: true
resource_class: arm.medium
steps:
- attach_workspace:
at: /tmp
- run:
name: Install deps
command: |
sudo apt update
sudo apt install groff less python3-pip
pip install awscli
- run:
name: Login to registries
command: |
echo ${DOCKERHUB_SECRET} | docker login -u ${DOCKERHUB_USER} --password-stdin
aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws/falcosecurity
- run:
name: Build and publish no-driver-dev
command: |
FALCO_VERSION=$(cat /tmp/build/release/userspace/falco/config_falco.h | grep 'FALCO_VERSION ' | cut -d' ' -f3 | sed -e 's/^"//' -e 's/"$//')
cd /tmp/source-arm64/falco
docker buildx build --push --build-arg VERSION_BUCKET=bin-dev --build-arg FALCO_VERSION=${FALCO_VERSION} \
-t falcosecurity/falco-no-driver:aarch64-master \
-t falcosecurity/falco:aarch64-master-slim \
-t public.ecr.aws/falcosecurity/falco-no-driver:aarch64-master \
-t public.ecr.aws/falcosecurity/falco:aarch64-master-slim \
docker/no-driver
- run:
name: Build and publish falco-dev
command: |
FALCO_VERSION=$(cat /tmp/build/release/userspace/falco/config_falco.h | grep 'FALCO_VERSION ' | cut -d' ' -f3 | sed -e 's/^"//' -e 's/"$//')
cd /tmp/source-arm64/falco
docker buildx build --push --build-arg VERSION_BUCKET=deb-dev --build-arg FALCO_VERSION=${FALCO_VERSION} \
-t falcosecurity/falco:aarch64-master \
-t public.ecr.aws/falcosecurity/falco:aarch64-master \
docker/falco
- run:
name: Build and publish falco-driver-loader-dev
command: |
cd /tmp/source-arm64/falco
docker buildx build --push --build-arg FALCO_IMAGE_TAG=master \
-t falcosecurity/falco-driver-loader:aarch64-master \
-t public.ecr.aws/falcosecurity/falco-driver-loader:aarch64-master \
docker/driver-loader
# Publish docker packages
"publish-docker-dev":
docker:
- image: cimg/base:stable
user: root
steps:
- attach_workspace:
at: /
- checkout
- setup_remote_docker:
version: 20.10.12
- run:
name: Prepare env
name: Install deps
command: |
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
docker context create falco-env
docker buildx create falco-env --driver docker-container --use
echo ${DOCKERHUB_SECRET} | docker login -u ${DOCKERHUB_USER} --password-stdin
sudo apt update
sudo apt install groff less python3-pip
pip install awscli
- run:
name: Login to aws ECR
name: Login to registries
command: |
echo ${DOCKERHUB_SECRET} | docker login -u ${DOCKERHUB_USER} --password-stdin
aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws/falcosecurity
- run:
name: Build and publish no-driver-dev
name: Upload no-driver-dev manifest to registries
command: |
FALCO_VERSION=$(cat /build/release/userspace/falco/config_falco.h | grep 'FALCO_VERSION ' | cut -d' ' -f3 | sed -e 's/^"//' -e 's/"$//')
docker buildx build --build-arg VERSION_BUCKET=bin-dev --build-arg FALCO_VERSION=${FALCO_VERSION} --platform "arm64,amd64" --push \
-t falcosecurity/falco-no-driver:master \
-t falcosecurity/falco:master-slim \
-t public.ecr.aws/falcosecurity/falco-no-driver:master \
-t public.ecr.aws/falcosecurity/falco:master-slim \
docker/no-driver
docker manifest create falcosecurity/falco-no-driver:master \
falcosecurity/falco-no-driver:aarch64-master \
falcosecurity/falco-no-driver:x86_64-master
docker manifest push falcosecurity/falco-no-driver:master
docker manifest create falcosecurity/falco:master-slim \
falcosecurity/falco:aarch64-master-slim \
falcosecurity/falco:x86_64-master-slim
docker manifest push falcosecurity/falco:master-slim
docker manifest create public.ecr.aws/falcosecurity/falco-no-driver:master \
public.ecr.aws/falcosecurity/falco-no-driver:aarch64-master \
public.ecr.aws/falcosecurity/falco-no-driver:x86_64-master
docker manifest push public.ecr.aws/falcosecurity/falco-no-driver:master
docker manifest create public.ecr.aws/falcosecurity/falco:master-slim \
public.ecr.aws/falcosecurity/falco:aarch64-master-slim \
public.ecr.aws/falcosecurity/falco:x86_64-master-slim
docker manifest push public.ecr.aws/falcosecurity/falco:master-slim
- run:
name: Build and publish dev
name: Upload falco-dev manifest to registries
command: |
FALCO_VERSION=$(cat /build/release/userspace/falco/config_falco.h | grep 'FALCO_VERSION ' | cut -d' ' -f3 | sed -e 's/^"//' -e 's/"$//')
docker buildx build --build-arg VERSION_BUCKET=deb-dev --build-arg FALCO_VERSION=${FALCO_VERSION} --platform "arm64,amd64" --push \
-t falcosecurity/falco:master \
-t public.ecr.aws/falcosecurity/falco:master \
docker/falco
docker manifest create falcosecurity/falco:master \
falcosecurity/falco:aarch64-master \
falcosecurity/falco:x86_64-master
docker manifest push falcosecurity/falco:master
docker manifest create public.ecr.aws/falcosecurity/falco:master \
public.ecr.aws/falcosecurity/falco:aarch64-master \
public.ecr.aws/falcosecurity/falco:x86_64-master
docker manifest push public.ecr.aws/falcosecurity/falco:master
- run:
name: Build and publish dev falco-driver-loader-dev
name: Upload falco-driver-loader-dev manifest to registries
command: |
docker buildx build --build-arg FALCO_IMAGE_TAG=master --platform "arm64,amd64" --push \
-t falcosecurity/falco-driver-loader:master \
-t public.ecr.aws/falcosecurity/falco-driver-loader:master \
docker/driver-loader
docker manifest create falcosecurity/falco-driver-loader:master \
falcosecurity/falco-driver-loader:aarch64-master \
falcosecurity/falco-driver-loader:x86_64-master
docker manifest push falcosecurity/falco-driver-loader:master
docker manifest create public.ecr.aws/falcosecurity/falco-driver-loader:master \
public.ecr.aws/falcosecurity/falco-driver-loader:aarch64-master \
public.ecr.aws/falcosecurity/falco-driver-loader:x86_64-master
docker manifest push public.ecr.aws/falcosecurity/falco-driver-loader:master
# Publish the packages
"publish-packages":
@@ -417,62 +530,222 @@ jobs:
command: |
FALCO_VERSION=$(cat /build/release/userspace/falco/config_falco.h | grep 'FALCO_VERSION ' | cut -d' ' -f3 | sed -e 's/^"//' -e 's/"$//')
/source/falco/scripts/publish-deb -f /build/release/falco-${FALCO_VERSION}-x86_64.deb -f /build-arm64/release/falco-${FALCO_VERSION}-aarch64.deb -r deb
"build-docker":
docker:
- image: alpine:3.16
steps:
- attach_workspace:
at: /
- setup_remote_docker:
version: 20.10.12
docker_layer_caching: true
- run:
name: Install deps
command: |
apk update
apk add make bash git docker docker-cli-buildx py3-pip
pip install awscli
- run:
name: Login to registries
command: |
echo ${DOCKERHUB_SECRET} | docker login -u ${DOCKERHUB_USER} --password-stdin
aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws/falcosecurity
- run:
name: Build and publish no-driver
command: |
cd /source/falco
docker buildx build --push --build-arg VERSION_BUCKET=bin-dev --build-arg FALCO_VERSION=${CIRCLE_TAG} \
-t "falcosecurity/falco-no-driver:x86_64-${CIRCLE_TAG}" \
-t falcosecurity/falco-no-driver:x86_64-latest \
-t "falcosecurity/falco:x86_64-${CIRCLE_TAG}-slim" \
-t "falcosecurity/falco:x86_64-latest-slim" \
-t "public.ecr.aws/falcosecurity/falco-no-driver:x86_64-${CIRCLE_TAG}" \
-t "public.ecr.aws/falcosecurity/falco-no-driver:x86_64-latest" \
-t "public.ecr.aws/falcosecurity/falco:x86_64-${CIRCLE_TAG}-slim" \
-t "public.ecr.aws/falcosecurity/falco:x86_64-latest-slim" \
docker/no-driver
- run:
name: Build and publish falco
command: |
cd /source/falco
docker buildx build --push --build-arg VERSION_BUCKET=deb-dev --build-arg FALCO_VERSION=${CIRCLE_TAG} \
-t "falcosecurity/falco:x86_64-${CIRCLE_TAG}" \
-t "falcosecurity/falco:x86_64-latest" \
-t "public.ecr.aws/falcosecurity/falco:x86_64-${CIRCLE_TAG}" \
-t "public.ecr.aws/falcosecurity/falco:x86_64-latest" \
docker/falco
- run:
name: Build and publish falco-driver-loader
command: |
cd /source/falco
docker buildx build --push --build-arg FALCO_IMAGE_TAG=${CIRCLE_TAG} \
-t "falcosecurity/falco-driver-loader:x86_64-${CIRCLE_TAG}" \
-t "falcosecurity/falco-driver-loader:x86_64-latest" \
-t "public.ecr.aws/falcosecurity/falco-driver-loader:x86_64-${CIRCLE_TAG}" \
-t "public.ecr.aws/falcosecurity/falco-driver-loader:x86_64-latest" \
docker/driver-loader
"build-docker-arm64":
machine:
enabled: true
image: ubuntu-2004:202101-01
docker_layer_caching: true
resource_class: arm.medium
steps:
- attach_workspace:
at: /tmp
- run:
name: Install deps
command: |
sudo apt update
sudo apt install groff less python3-pip
pip install awscli
- run:
name: Login to registries
command: |
echo ${DOCKERHUB_SECRET} | docker login -u ${DOCKERHUB_USER} --password-stdin
aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws/falcosecurity
- run:
name: Build and publish no-driver
command: |
cd /tmp/source-arm64/falco
docker buildx build --push --build-arg VERSION_BUCKET=bin --build-arg FALCO_VERSION=${CIRCLE_TAG} \
-t falcosecurity/falco-no-driver:aarch64-${CIRCLE_TAG} \
-t falcosecurity/falco-no-driver:aarch64-latest \
-t falcosecurity/falco:aarch64-${CIRCLE_TAG}-slim \
-t "falcosecurity/falco:aarch64-latest-slim" \
-t public.ecr.aws/falcosecurity/falco-no-driver:aarch64-${CIRCLE_TAG} \
-t "public.ecr.aws/falcosecurity/falco-no-driver:aarch64-latest" \
-t public.ecr.aws/falcosecurity/falco:aarch64-${CIRCLE_TAG}-slim \
-t "public.ecr.aws/falcosecurity/falco:aarch64-latest-slim" \
docker/no-driver
- run:
name: Build and publish falco
command: |
cd /tmp/source-arm64/falco
docker buildx build --push --build-arg VERSION_BUCKET=deb-dev --build-arg FALCO_VERSION=${CIRCLE_TAG} \
-t "falcosecurity/falco:aarch64-${CIRCLE_TAG}" \
-t "falcosecurity/falco:aarch64-latest" \
-t "public.ecr.aws/falcosecurity/falco:aarch64-${CIRCLE_TAG}" \
-t "public.ecr.aws/falcosecurity/falco:aarch64-latest" \
docker/falco
- run:
name: Build and publish falco-driver-loader
command: |
cd /tmp/source-arm64/falco
docker buildx build --push --build-arg FALCO_IMAGE_TAG=${CIRCLE_TAG} \
-t "falcosecurity/falco-driver-loader:aarch64-${CIRCLE_TAG}" \
-t "falcosecurity/falco-driver-loader:aarch64-latest" \
-t "public.ecr.aws/falcosecurity/falco-driver-loader:aarch64-${CIRCLE_TAG}" \
-t "public.ecr.aws/falcosecurity/falco-driver-loader:aarch64-latest" \
docker/driver-loader
# Publish docker packages
"publish-docker":
docker:
- image: cimg/base:stable
user: root
steps:
- attach_workspace:
at: /
- checkout
- setup_remote_docker:
version: 20.10.12
- run:
name: Prepare env
name: Install deps
command: |
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
docker context create falco-env
docker buildx create falco-env --driver docker-container --use
echo ${DOCKERHUB_SECRET} | docker login -u ${DOCKERHUB_USER} --password-stdin
sudo apt update
sudo apt install groff less python3-pip
pip install awscli
- run:
name: Login to aws ECR
name: Login to registries
command: |
echo ${DOCKERHUB_SECRET} | docker login -u ${DOCKERHUB_USER} --password-stdin
aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws/falcosecurity
- run:
name: Build and publish no-driver
name: Upload no-driver manifest to registries
command: |
docker buildx build --build-arg VERSION_BUCKET=bin --build-arg FALCO_VERSION=${CIRCLE_TAG} --platform "arm64,amd64" --push \
-t "falcosecurity/falco-no-driver:${CIRCLE_TAG}" \
-t falcosecurity/falco-no-driver:latest \
-t "falcosecurity/falco:${CIRCLE_TAG}-slim" \
-t "falcosecurity/falco:latest-slim" \
-t "public.ecr.aws/falcosecurity/falco-no-driver:${CIRCLE_TAG}" \
-t "public.ecr.aws/falcosecurity/falco-no-driver:latest" \
-t "public.ecr.aws/falcosecurity/falco:${CIRCLE_TAG}-slim" \
-t "public.ecr.aws/falcosecurity/falco:latest-slim" \
docker/no-driver
docker manifest create falcosecurity/falco-no-driver:${CIRCLE_TAG} \
falcosecurity/falco-no-driver:aarch64-${CIRCLE_TAG} \
falcosecurity/falco-no-driver:x86_64-${CIRCLE_TAG}
docker manifest push falcosecurity/falco-no-driver:${CIRCLE_TAG}
docker manifest create falcosecurity/falco-no-driver:latest \
falcosecurity/falco-no-driver:aarch64-latest \
falcosecurity/falco-no-driver:x86_64-latest
docker manifest push falcosecurity/falco-no-driver:latest
docker manifest create falcosecurity/falco:${CIRCLE_TAG}-slim \
falcosecurity/falco:aarch64-${CIRCLE_TAG}-slim \
falcosecurity/falco:x86_64-${CIRCLE_TAG}-slim
docker manifest push falcosecurity/falco:${CIRCLE_TAG}-slim
docker manifest create falcosecurity/falco:latest-slim \
falcosecurity/falco:aarch64-latest-slim \
falcosecurity/falco:x86_64-latest-slim
docker manifest push falcosecurity/falco:latest-slim
docker manifest create public.ecr.aws/falcosecurity/falco-no-driver:${CIRCLE_TAG} \
public.ecr.aws/falcosecurity/falco-no-driver:aarch64-${CIRCLE_TAG} \
public.ecr.aws/falcosecurity/falco-no-driver:x86_64-${CIRCLE_TAG}
docker manifest push public.ecr.aws/falcosecurity/falco-no-driver:${CIRCLE_TAG}
docker manifest create public.ecr.aws/falcosecurity/falco-no-driver:latest \
public.ecr.aws/falcosecurity/falco-no-driver:aarch64-latest \
public.ecr.aws/falcosecurity/falco-no-driver:x86_64-latest
docker manifest push public.ecr.aws/falcosecurity/falco-no-driver:latest
docker manifest create public.ecr.aws/falcosecurity/falco:${CIRCLE_TAG}-slim \
public.ecr.aws/falcosecurity/falco:aarch64-${CIRCLE_TAG}-slim \
public.ecr.aws/falcosecurity/falco:x86_64-${CIRCLE_TAG}-slim
docker manifest push public.ecr.aws/falcosecurity/falco:${CIRCLE_TAG}-slim
docker manifest create public.ecr.aws/falcosecurity/falco:latest-slim \
public.ecr.aws/falcosecurity/falco:aarch64-latest-slim \
public.ecr.aws/falcosecurity/falco:x86_64-latest-slim
docker manifest push public.ecr.aws/falcosecurity/falco:latest-slim
- run:
name: Build and publish falco
name: Upload falco manifest to registries
command: |
docker buildx build --build-arg VERSION_BUCKET=deb --build-arg FALCO_VERSION=${CIRCLE_TAG} --platform "arm64,amd64" --push \
-t "falcosecurity/falco:${CIRCLE_TAG}" \
-t "falcosecurity/falco:latest" \
-t "public.ecr.aws/falcosecurity/falco:${CIRCLE_TAG}" \
-t "public.ecr.aws/falcosecurity/falco:latest" \
docker/falco
docker manifest create falcosecurity/falco:${CIRCLE_TAG} \
falcosecurity/falco:aarch64-${CIRCLE_TAG} \
falcosecurity/falco:x86_64-${CIRCLE_TAG}
docker manifest push falcosecurity/falco:${CIRCLE_TAG}
docker manifest create falcosecurity/falco:latest \
falcosecurity/falco:aarch64-latest \
falcosecurity/falco:x86_64-latest
docker manifest push falcosecurity/falco:latest
docker manifest create public.ecr.aws/falcosecurity/falco:${CIRCLE_TAG} \
public.ecr.aws/falcosecurity/falco:aarch64-${CIRCLE_TAG} \
public.ecr.aws/falcosecurity/falco:x86_64-${CIRCLE_TAG}
docker manifest push public.ecr.aws/falcosecurity/falco:${CIRCLE_TAG}
docker manifest create public.ecr.aws/falcosecurity/falco:latest \
public.ecr.aws/falcosecurity/falco:aarch64-latest \
public.ecr.aws/falcosecurity/falco:x86_64-latest
docker manifest push public.ecr.aws/falcosecurity/falco:latest
- run:
name: Build and publish falco-driver-loader
name: Upload falco-driver-loader manifest to registries
command: |
docker buildx build --build-arg FALCO_IMAGE_TAG=${CIRCLE_TAG} --platform "arm64,amd64" --push \
-t "falcosecurity/falco-driver-loader:${CIRCLE_TAG}" \
-t "falcosecurity/falco-driver-loader:latest" \
-t "public.ecr.aws/falcosecurity/falco-driver-loader:${CIRCLE_TAG}" \
-t "public.ecr.aws/falcosecurity/falco-driver-loader:latest" \
docker/driver-loader
docker manifest create falcosecurity/falco-driver-loader:${CIRCLE_TAG} \
falcosecurity/falco-driver-loader:aarch64-${CIRCLE_TAG} \
falcosecurity/falco-driver-loader:x86_64-${CIRCLE_TAG}
docker manifest push falcosecurity/falco-driver-loader:${CIRCLE_TAG}
docker manifest create falcosecurity/falco-driver-loader:latest \
falcosecurity/falco-driver-loader:aarch64-latest \
falcosecurity/falco-driver-loader:x86_64-latest
docker manifest push falcosecurity/falco-driver-loader:latest
docker manifest create public.ecr.aws/falcosecurity/falco-driver-loader:${CIRCLE_TAG} \
public.ecr.aws/falcosecurity/falco-driver-loader:aarch64-${CIRCLE_TAG} \
public.ecr.aws/falcosecurity/falco-driver-loader:x86_64-${CIRCLE_TAG}
docker manifest push public.ecr.aws/falcosecurity/falco-driver-loader:${CIRCLE_TAG}
docker manifest create public.ecr.aws/falcosecurity/falco-driver-loader:latest \
public.ecr.aws/falcosecurity/falco-driver-loader:aarch64-latest \
public.ecr.aws/falcosecurity/falco-driver-loader:x86_64-latest
docker manifest push public.ecr.aws/falcosecurity/falco-driver-loader:latest
workflows:
version: 2.1
@@ -527,7 +800,7 @@ workflows:
requires:
- "tests-integration"
- "tests-integration-arm64"
- "publish-docker-dev":
- "build-docker-dev":
context:
- falco
- test-infra
@@ -540,6 +813,31 @@ workflows:
- "publish-packages-dev"
- "publish-packages-deb-dev"
- "tests-driver-loader-integration"
- "build-docker-dev-arm64":
context:
- falco
- test-infra
filters:
tags:
ignore: /.*/
branches:
only: master
requires:
- "publish-packages-dev"
- "publish-packages-deb-dev"
- "tests-driver-loader-integration"
- "publish-docker-dev":
context:
- falco
- test-infra
filters:
tags:
ignore: /.*/
branches:
only: master
requires:
- "build-docker-dev"
- "build-docker-dev-arm64"
# - "quality/static-analysis" # This is temporarily disabled: https://github.com/falcosecurity/falco/issues/1526
release:
jobs:
@@ -595,7 +893,7 @@ workflows:
only: /.*/
branches:
ignore: /.*/
- "publish-docker":
- "build-docker":
context:
- falco
- test-infra
@@ -607,3 +905,27 @@ workflows:
only: /.*/
branches:
ignore: /.*/
- "build-docker-arm64":
context:
- falco
- test-infra
requires:
- "publish-packages"
- "publish-packages-deb"
filters:
tags:
only: /.*/
branches:
ignore: /.*/
- "publish-docker":
context:
- falco
- test-infra
requires:
- "build-docker"
- "build-docker-arm64"
filters:
tags:
only: /.*/
branches:
ignore: /.*/

View File

@@ -56,6 +56,9 @@ if(NOT DEFINED FALCO_ETC_DIR)
set(FALCO_ETC_DIR "${CMAKE_INSTALL_FULL_SYSCONFDIR}/falco")
endif()
# This will be used to print the architecture for which Falco is compiled.
set(FALCO_TARGET_ARCH ${CMAKE_SYSTEM_PROCESSOR})
if(NOT DRAIOS_DEBUG_FLAGS)
set(DRAIOS_DEBUG_FLAGS "-D_DEBUG")
endif()

12
OWNERS
View File

@@ -1,18 +1,12 @@
approvers:
- fntlnz
- kris-nova
- leodido
- mstemm
- leogr
- jasondellaluce
- fededp
reviewers:
- fntlnz
- kaizhe
- mfdii
emeritus_approvers:
- fntlnz
- kris-nova
- leodido
- mfdii
- mstemm
- leogr
- jasondellaluce
- fededp

View File

@@ -51,12 +51,12 @@ Notes:
| | development | stable |
|--------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| rpm | [![rpm-dev](https://img.shields.io/badge/dynamic/xml?color=%2300aec7&style=flat-square&label=Falco&query=substring-before%28substring-after%28%28%2F%2A%5Bname%28%29%3D%27ListBucketResult%27%5D%2F%2A%5Bname%28%29%3D%27Contents%27%5D%29%5Blast%28%29%5D%2F%2A%5Bname%28%29%3D%27Key%27%5D%2C%22falco-%22%29%2C%22.asc%22%29&url=https%3A%2F%2Ffalco-distribution.s3-eu-west-1.amazonaws.com%2F%3Fprefix%3Dpackages%2Frpm-dev%2Ffalco-%26delimiter=aarch64)][1] | [![rpm](https://img.shields.io/badge/dynamic/xml?color=%2300aec7&style=flat-square&label=Falco&query=substring-before%28substring-after%28%28%2F%2A%5Bname%28%29%3D%27ListBucketResult%27%5D%2F%2A%5Bname%28%29%3D%27Contents%27%5D%29%5Blast%28%29%5D%2F%2A%5Bname%28%29%3D%27Key%27%5D%2C%22falco-%22%29%2C%22.asc%22%29&url=https%3A%2F%2Ffalco-distribution.s3-eu-west-1.amazonaws.com%2F%3Fprefix%3Dpackages%2Frpm%2Ffalco-%26delimiter=aarch64)][2] |
| deb | [![deb-dev](https://img.shields.io/badge/dynamic/xml?color=%2300aec7&style=flat-square&label=Falco&query=substring-before%28substring-after%28%28%2F%2A%5Bname%28%29%3D%27ListBucketResult%27%5D%2F%2A%5Bname%28%29%3D%27Contents%27%5D%29%5Blast%28%29%5D%2F%2A%5Bname%28%29%3D%27Key%27%5D%2C%22falco-%22%29%2C%22.asc%22%29&url=https%3A%2F%2Ffalco-distribution.s3-eu-west-1.amazonaws.com%2F%3Fprefix%3Dpackages%2Fdeb-dev%2Fstable%2Ffalco-%26delimiter=aarch64)][3] | [![deb](https://img.shields.io/badge/dynamic/xml?color=%2300aec7&style=flat-square&label=Falco&query=substring-before%28substring-after%28%28%2F%2A%5Bname%28%29%3D%27ListBucketResult%27%5D%2F%2A%5Bname%28%29%3D%27Contents%27%5D%29%5Blast%28%29%5D%2F%2A%5Bname%28%29%3D%27Key%27%5D%2C%22falco-%22%29%2C%22.asc%22%29&url=https%3A%2F%2Ffalco-distribution.s3-eu-west-1.amazonaws.com%2F%3Fprefix%3Dpackages%2Fdeb%2Fstable%2Ffalco-%26delimiter=aarch64)][4] |
| binary | [![bin-dev](https://img.shields.io/badge/dynamic/xml?color=%2300aec7&style=flat-square&label=Falco&query=substring-after%28%28%2F%2A%5Bname%28%29%3D%27ListBucketResult%27%5D%2F%2A%5Bname%28%29%3D%27Contents%27%5D%29%5Blast%28%29%5D%2F%2A%5Bname%28%29%3D%27Key%27%5D%2C%20%22falco-%22%29&url=https%3A%2F%2Ffalco-distribution.s3-eu-west-1.amazonaws.com%2F%3Fprefix%3Dpackages%2Fbin-dev%2Fx86_64%2Ffalco-)][5] | [![bin](https://img.shields.io/badge/dynamic/xml?color=%2300aec7&style=flat-square&label=Falco&query=substring-after%28%28%2F%2A%5Bname%28%29%3D%27ListBucketResult%27%5D%2F%2A%5Bname%28%29%3D%27Contents%27%5D%29%5Blast%28%29%5D%2F%2A%5Bname%28%29%3D%27Key%27%5D%2C%20%22falco-%22%29&url=https%3A%2F%2Ffalco-distribution.s3-eu-west-1.amazonaws.com%2F%3Fprefix%3Dpackages%2Fbin%2Fx86_64%2Ffalco-)][6] |
| rpm-arm64 | [![rpm-dev](https://img.shields.io/badge/dynamic/xml?color=%2300aec7&style=flat-square&label=Falco&query=substring-before%28substring-after%28%28%2F%2A%5Bname%28%29%3D%27ListBucketResult%27%5D%2F%2A%5Bname%28%29%3D%27Contents%27%5D%29%5Blast%28%29%5D%2F%2A%5Bname%28%29%3D%27Key%27%5D%2C%22falco-%22%29%2C%22.asc%22%29&url=https%3A%2F%2Ffalco-distribution.s3-eu-west-1.amazonaws.com%2F%3Fprefix%3Dpackages%2Frpm-dev%2Ffalco-%26delimiter=x86_64)][1] | [![rpm](https://img.shields.io/badge/dynamic/xml?color=%2300aec7&style=flat-square&label=Falco&query=substring-before%28substring-after%28%28%2F%2A%5Bname%28%29%3D%27ListBucketResult%27%5D%2F%2A%5Bname%28%29%3D%27Contents%27%5D%29%5Blast%28%29%5D%2F%2A%5Bname%28%29%3D%27Key%27%5D%2C%22falco-%22%29%2C%22.asc%22%29&url=https%3A%2F%2Ffalco-distribution.s3-eu-west-1.amazonaws.com%2F%3Fprefix%3Dpackages%2Frpm%2Ffalco-%26delimiter=x86_64)][2] |
| deb-arm64 | [![deb-dev](https://img.shields.io/badge/dynamic/xml?color=%2300aec7&style=flat-square&label=Falco&query=substring-before%28substring-after%28%28%2F%2A%5Bname%28%29%3D%27ListBucketResult%27%5D%2F%2A%5Bname%28%29%3D%27Contents%27%5D%29%5Blast%28%29%5D%2F%2A%5Bname%28%29%3D%27Key%27%5D%2C%22falco-%22%29%2C%22.asc%22%29&url=https%3A%2F%2Ffalco-distribution.s3-eu-west-1.amazonaws.com%2F%3Fprefix%3Dpackages%2Fdeb-dev%2Fstable%2Ffalco-%26delimiter=x86_64)][3] | [![deb](https://img.shields.io/badge/dynamic/xml?color=%2300aec7&style=flat-square&label=Falco&query=substring-before%28substring-after%28%28%2F%2A%5Bname%28%29%3D%27ListBucketResult%27%5D%2F%2A%5Bname%28%29%3D%27Contents%27%5D%29%5Blast%28%29%5D%2F%2A%5Bname%28%29%3D%27Key%27%5D%2C%22falco-%22%29%2C%22.asc%22%29&url=https%3A%2F%2Ffalco-distribution.s3-eu-west-1.amazonaws.com%2F%3Fprefix%3Dpackages%2Fdeb%2Fstable%2Ffalco-%26delimiter=x86_64)][4] |
| binary-arm64 | [![bin-dev](https://img.shields.io/badge/dynamic/xml?color=%2300aec7&style=flat-square&label=Falco&query=substring-after%28%28%2F%2A%5Bname%28%29%3D%27ListBucketResult%27%5D%2F%2A%5Bname%28%29%3D%27Contents%27%5D%29%5Blast%28%29%5D%2F%2A%5Bname%28%29%3D%27Key%27%5D%2C%20%22falco-%22%29&url=https%3A%2F%2Ffalco-distribution.s3-eu-west-1.amazonaws.com%2F%3Fprefix%3Dpackages%2Fbin-dev%2Faarch64%2Ffalco-)][7] | [![bin](https://img.shields.io/badge/dynamic/xml?color=%2300aec7&style=flat-square&label=Falco&query=substring-after%28%28%2F%2A%5Bname%28%29%3D%27ListBucketResult%27%5D%2F%2A%5Bname%28%29%3D%27Contents%27%5D%29%5Blast%28%29%5D%2F%2A%5Bname%28%29%3D%27Key%27%5D%2C%20%22falco-%22%29&url=https%3A%2F%2Ffalco-distribution.s3-eu-west-1.amazonaws.com%2F%3Fprefix%3Dpackages%2Fbin%2Faarch64%2Ffalco-)][8] |
| rpm-x86_64 | [![rpm-dev](https://img.shields.io/badge/dynamic/xml?color=%2300aec7&style=flat-square&label=Falco&query=substring-before%28substring-after%28%28%2F%2A%5Bname%28%29%3D%27ListBucketResult%27%5D%2F%2A%5Bname%28%29%3D%27Contents%27%5D%29%5Blast%28%29%5D%2F%2A%5Bname%28%29%3D%27Key%27%5D%2C%22falco-%22%29%2C%22.asc%22%29&url=https%3A%2F%2Ffalco-distribution.s3-eu-west-1.amazonaws.com%2F%3Fprefix%3Dpackages%2Frpm-dev%2Ffalco-%26delimiter=aarch64)][1] | [![rpm](https://img.shields.io/badge/dynamic/xml?color=%2300aec7&style=flat-square&label=Falco&query=substring-before%28substring-after%28%28%2F%2A%5Bname%28%29%3D%27ListBucketResult%27%5D%2F%2A%5Bname%28%29%3D%27Contents%27%5D%29%5Blast%28%29%5D%2F%2A%5Bname%28%29%3D%27Key%27%5D%2C%22falco-%22%29%2C%22.asc%22%29&url=https%3A%2F%2Ffalco-distribution.s3-eu-west-1.amazonaws.com%2F%3Fprefix%3Dpackages%2Frpm%2Ffalco-%26delimiter=aarch64)][2] |
| deb-x86_64 | [![deb-dev](https://img.shields.io/badge/dynamic/xml?color=%2300aec7&style=flat-square&label=Falco&query=substring-before%28substring-after%28%28%2F%2A%5Bname%28%29%3D%27ListBucketResult%27%5D%2F%2A%5Bname%28%29%3D%27Contents%27%5D%29%5Blast%28%29%5D%2F%2A%5Bname%28%29%3D%27Key%27%5D%2C%22falco-%22%29%2C%22.asc%22%29&url=https%3A%2F%2Ffalco-distribution.s3-eu-west-1.amazonaws.com%2F%3Fprefix%3Dpackages%2Fdeb-dev%2Fstable%2Ffalco-%26delimiter=aarch64)][3] | [![deb](https://img.shields.io/badge/dynamic/xml?color=%2300aec7&style=flat-square&label=Falco&query=substring-before%28substring-after%28%28%2F%2A%5Bname%28%29%3D%27ListBucketResult%27%5D%2F%2A%5Bname%28%29%3D%27Contents%27%5D%29%5Blast%28%29%5D%2F%2A%5Bname%28%29%3D%27Key%27%5D%2C%22falco-%22%29%2C%22.asc%22%29&url=https%3A%2F%2Ffalco-distribution.s3-eu-west-1.amazonaws.com%2F%3Fprefix%3Dpackages%2Fdeb%2Fstable%2Ffalco-%26delimiter=aarch64)][4] |
| binary-x86_64 | [![bin-dev](https://img.shields.io/badge/dynamic/xml?color=%2300aec7&style=flat-square&label=Falco&query=substring-after%28%28%2F%2A%5Bname%28%29%3D%27ListBucketResult%27%5D%2F%2A%5Bname%28%29%3D%27Contents%27%5D%29%5Blast%28%29%5D%2F%2A%5Bname%28%29%3D%27Key%27%5D%2C%20%22falco-%22%29&url=https%3A%2F%2Ffalco-distribution.s3-eu-west-1.amazonaws.com%2F%3Fprefix%3Dpackages%2Fbin-dev%2Fx86_64%2Ffalco-)][5] | [![bin](https://img.shields.io/badge/dynamic/xml?color=%2300aec7&style=flat-square&label=Falco&query=substring-after%28%28%2F%2A%5Bname%28%29%3D%27ListBucketResult%27%5D%2F%2A%5Bname%28%29%3D%27Contents%27%5D%29%5Blast%28%29%5D%2F%2A%5Bname%28%29%3D%27Key%27%5D%2C%20%22falco-%22%29&url=https%3A%2F%2Ffalco-distribution.s3-eu-west-1.amazonaws.com%2F%3Fprefix%3Dpackages%2Fbin%2Fx86_64%2Ffalco-)][6] |
| rpm-aarch64 | [![rpm-dev](https://img.shields.io/badge/dynamic/xml?color=%2300aec7&style=flat-square&label=Falco&query=substring-before%28substring-after%28%28%2F%2A%5Bname%28%29%3D%27ListBucketResult%27%5D%2F%2A%5Bname%28%29%3D%27Contents%27%5D%29%5Blast%28%29%5D%2F%2A%5Bname%28%29%3D%27Key%27%5D%2C%22falco-%22%29%2C%22.asc%22%29&url=https%3A%2F%2Ffalco-distribution.s3-eu-west-1.amazonaws.com%2F%3Fprefix%3Dpackages%2Frpm-dev%2Ffalco-%26delimiter=x86_64)][1] | [![rpm](https://img.shields.io/badge/dynamic/xml?color=%2300aec7&style=flat-square&label=Falco&query=substring-before%28substring-after%28%28%2F%2A%5Bname%28%29%3D%27ListBucketResult%27%5D%2F%2A%5Bname%28%29%3D%27Contents%27%5D%29%5Blast%28%29%5D%2F%2A%5Bname%28%29%3D%27Key%27%5D%2C%22falco-%22%29%2C%22.asc%22%29&url=https%3A%2F%2Ffalco-distribution.s3-eu-west-1.amazonaws.com%2F%3Fprefix%3Dpackages%2Frpm%2Ffalco-%26delimiter=x86_64)][2] |
| deb-aarch64 | [![deb-dev](https://img.shields.io/badge/dynamic/xml?color=%2300aec7&style=flat-square&label=Falco&query=substring-before%28substring-after%28%28%2F%2A%5Bname%28%29%3D%27ListBucketResult%27%5D%2F%2A%5Bname%28%29%3D%27Contents%27%5D%29%5Blast%28%29%5D%2F%2A%5Bname%28%29%3D%27Key%27%5D%2C%22falco-%22%29%2C%22.asc%22%29&url=https%3A%2F%2Ffalco-distribution.s3-eu-west-1.amazonaws.com%2F%3Fprefix%3Dpackages%2Fdeb-dev%2Fstable%2Ffalco-%26delimiter=x86_64)][3] | [![deb](https://img.shields.io/badge/dynamic/xml?color=%2300aec7&style=flat-square&label=Falco&query=substring-before%28substring-after%28%28%2F%2A%5Bname%28%29%3D%27ListBucketResult%27%5D%2F%2A%5Bname%28%29%3D%27Contents%27%5D%29%5Blast%28%29%5D%2F%2A%5Bname%28%29%3D%27Key%27%5D%2C%22falco-%22%29%2C%22.asc%22%29&url=https%3A%2F%2Ffalco-distribution.s3-eu-west-1.amazonaws.com%2F%3Fprefix%3Dpackages%2Fdeb%2Fstable%2Ffalco-%26delimiter=x86_64)][4] |
| binary-aarch64 | [![bin-dev](https://img.shields.io/badge/dynamic/xml?color=%2300aec7&style=flat-square&label=Falco&query=substring-after%28%28%2F%2A%5Bname%28%29%3D%27ListBucketResult%27%5D%2F%2A%5Bname%28%29%3D%27Contents%27%5D%29%5Blast%28%29%5D%2F%2A%5Bname%28%29%3D%27Key%27%5D%2C%20%22falco-%22%29&url=https%3A%2F%2Ffalco-distribution.s3-eu-west-1.amazonaws.com%2F%3Fprefix%3Dpackages%2Fbin-dev%2Faarch64%2Ffalco-)][7] | [![bin](https://img.shields.io/badge/dynamic/xml?color=%2300aec7&style=flat-square&label=Falco&query=substring-after%28%28%2F%2A%5Bname%28%29%3D%27ListBucketResult%27%5D%2F%2A%5Bname%28%29%3D%27Contents%27%5D%29%5Blast%28%29%5D%2F%2A%5Bname%28%29%3D%27Key%27%5D%2C%20%22falco-%22%29&url=https%3A%2F%2Ffalco-distribution.s3-eu-west-1.amazonaws.com%2F%3Fprefix%3Dpackages%2Fbin%2Faarch64%2Ffalco-)][8] |
---
@@ -164,4 +164,4 @@ Falco is licensed to you under the [Apache 2.0](./COPYING) open source license.
[5]: https://download.falco.org/?prefix=packages/bin-dev/x86_64/
[6]: https://download.falco.org/?prefix=packages/bin/x86_64/
[7]: https://download.falco.org/?prefix=packages/bin-dev/aarch64/
[8]: https://download.falco.org/?prefix=packages/bin/aarch64/
[8]: https://download.falco.org/?prefix=packages/bin/aarch64/

View File

@@ -68,9 +68,12 @@ Now assume `x.y.z` is the new version.
| Packages | Download |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| rpm | [![rpm](https://img.shields.io/badge/Falco-x.y.z-%2300aec7?style=flat-square)](https://download.falco.org/packages/rpm/falco-x.y.z-x86_64.rpm) |
| deb | [![deb](https://img.shields.io/badge/Falco-x.y.z-%2300aec7?style=flat-square)](https://download.falco.org/packages/deb/stable/falco-x.y.z-x86_64.deb) |
| tgz | [![tgz](https://img.shields.io/badge/Falco-x.y.z-%2300aec7?style=flat-square)](https://download.falco.org/packages/bin/x86_64/falco-x.y.z-x86_64.tar.gz) |
| rpm-x86_64 | [![rpm](https://img.shields.io/badge/Falco-x.y.z-%2300aec7?style=flat-square)](https://download.falco.org/packages/rpm/falco-x.y.z-x86_64.rpm) |
| deb-x86_64 | [![deb](https://img.shields.io/badge/Falco-x.y.z-%2300aec7?style=flat-square)](https://download.falco.org/packages/deb/stable/falco-x.y.z-x86_64.deb) |
| tgz-x86_64 | [![tgz](https://img.shields.io/badge/Falco-x.y.z-%2300aec7?style=flat-square)](https://download.falco.org/packages/bin/x86_64/falco-x.y.z-x86_64.tar.gz) |
| rpm-aarch64 | [![rpm](https://img.shields.io/badge/Falco-x.y.z-%2300aec7?style=flat-square)](https://download.falco.org/packages/rpm/falco-x.y.z-aarch64.rpm) |
| deb-aarch64 | [![deb](https://img.shields.io/badge/Falco-x.y.z-%2300aec7?style=flat-square)](https://download.falco.org/packages/deb/stable/falco-x.y.z-aarch64.deb) |
| tgz-aarch64 | [![tgz](https://img.shields.io/badge/Falco-x.y.z-%2300aec7?style=flat-square)](https://download.falco.org/packages/bin/aarch64/falco-x.y.z-aarch64.tar.gz) |
| Images |
| --------------------------------------------------------------------------- |

View File

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

View File

@@ -27,8 +27,8 @@ else()
# In case you want to test against another falcosecurity/libs version (or branch, or commit) just pass the variable -
# ie., `cmake -DFALCOSECURITY_LIBS_VERSION=dev ..`
if(NOT FALCOSECURITY_LIBS_VERSION)
set(FALCOSECURITY_LIBS_VERSION "0.7.0")
set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=3adc1620c0e830554a54cdd486158dc2c0c40552e113785b70fbbc99edb7d96f")
set(FALCOSECURITY_LIBS_VERSION "b4c198773bf05486e122f6d3f7f63be125242413")
set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=e85fa42a0b58ba21ca7efb38c20ce25207f4816245bdf154e6b9a037a1cce930")
endif()
# cd /path/to/build && cmake /path/to/source
@@ -68,6 +68,7 @@ set(BUILD_LIBSCAP_EXAMPLES OFF CACHE BOOL "")
set(USE_BUNDLED_TBB ON CACHE BOOL "")
set(USE_BUNDLED_B64 ON CACHE BOOL "")
set(USE_BUNDLED_JSONCPP ON CACHE BOOL "")
set(USE_BUNDLED_VALIJSON ON CACHE BOOL "")
list(APPEND CMAKE_MODULE_PATH "${FALCOSECURITY_LIBS_SOURCE_DIR}/cmake/modules")

View File

@@ -2,5 +2,4 @@ labels:
- area/integration
approvers:
- leogr
reviewers:
- leogr

View File

@@ -73,7 +73,9 @@ watch_config_files: true
# time zone, as governed by /etc/localtime.
time_format_iso_8601: false
# Whether to output events in json or text
# If "true", print falco alert messages and rules file
# loading/validation results as json, which allows for easier
# consumption by downstream programs. Default is "false".
json_output: false
# When using json output, whether or not to include the "output" property

View File

@@ -5,7 +5,6 @@ reviewers:
- fntlnz
- mfdii
- kaizhe
- mstemm
- darryk10
labels:
- area/rules

View File

@@ -360,6 +360,7 @@
- rule: Disallowed SSH Connection
desc: Detect any new ssh connection to a host other than those in an allowed group of hosts
condition: (inbound_outbound) and ssh_port and not allowed_ssh_hosts
enabled: false
output: Disallowed SSH Connection (command=%proc.cmdline connection=%fd.name user=%user.name user_loginuid=%user.loginuid container_id=%container.id image=%container.image.repository)
priority: NOTICE
tags: [network, mitre_remote_service]
@@ -510,7 +511,7 @@
# %container.info, without any leading term (file=%fd.name
# %container.info user=%user.name user_loginuid=%user.loginuid, and not file=%fd.name
# container=%container.info user=%user.name user_loginuid=%user.loginuid). The output will change
# based on the context and whether or not -pk/-pm/-pc was specified on
# based on the context and whether or not -pk/-pc was specified on
# the command line.
- macro: container
condition: (container.id != host)
@@ -959,9 +960,6 @@
# This rule is disabled by default as many system management tools
# like ansible, etc can read these files/paths. Enable it using this macro.
- macro: consider_ssh_reads
condition: (never_true)
- macro: user_known_read_ssh_information_activities
condition: (never_true)
@@ -969,10 +967,10 @@
desc: Any attempt to read files below ssh directories by non-ssh programs
condition: >
((open_read or open_directory) and
consider_ssh_reads and
(user_ssh_directory or fd.name startswith /root/.ssh) and
not user_known_read_ssh_information_activities and
not proc.name in (ssh_binaries))
enabled: false
output: >
ssh-related file/directory read by non-ssh program (user=%user.name user_loginuid=%user.loginuid
command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline container_id=%container.id image=%container.image.repository)
@@ -1148,6 +1146,9 @@
- macro: user_known_write_below_etc_activities
condition: (never_true)
- macro: calico_node
condition: (container.image.repository endswith calico/node and proc.name=calico-node)
- macro: write_etc_common
condition: >
etc_dir and evt.dir = < and open_write
@@ -1253,6 +1254,7 @@
and not mcafee_writing_cma_d
and not avinetworks_supervisor_writing_ssh
and not multipath_writing_conf
and not calico_node
- rule: Write below etc
desc: an attempt to write to any file below /etc
@@ -1471,7 +1473,7 @@
tags: [filesystem, software_mgmt, mitre_persistence]
- macro: postgres_running_wal_e
condition: (proc.pname=postgres and proc.cmdline startswith "sh -c envdir /etc/wal-e.d/env /usr/local/bin/wal-e")
condition: (proc.pname=postgres and (proc.cmdline startswith "sh -c envdir /etc/wal-e.d/env /usr/local/bin/wal-e" or proc.cmdline startswith "sh -c envdir \"/run/etc/wal-e.d/env\" wal-g wal-push"))
- macro: redis_running_prepost_scripts
condition: (proc.aname[2]=redis-server and (proc.cmdline contains "redis-server.post-up.d" or proc.cmdline contains "redis-server.pre-up.d"))
@@ -1550,9 +1552,6 @@
- list: network_plugin_binaries
items: [aws-cni, azure-vnet]
- macro: calico_node
condition: (container.image.repository endswith calico/node and proc.name=calico-node)
- macro: weaveworks_scope
condition: (container.image.repository endswith weaveworks/scope and proc.name=scope)
@@ -1759,6 +1758,13 @@
container.image.repository endswith /prometheus-node-exporter or
container.image.repository endswith /image-inspector))
- list: redhat_io_images_privileged
items: [registry.redhat.io/openshift-logging/fluentd-rhel8, registry.redhat.io/openshift4/ose-csi-node-driver-registrar, registry.redhat.io/openshift4/ose-kubernetes-nmstate-handler-rhel8, registry.redhat.io/openshift4/ose-local-storage-diskmaker]
- macro: redhat_image
condition: >
(container.image.repository in (redhat_io_images_privileged))
# https://docs.aws.amazon.com/eks/latest/userguide/add-ons-images.html
# official AWS EKS registry list. AWS has different ECR repo per region
- macro: allowed_aws_ecr_registry_root_for_eks
@@ -1841,7 +1847,8 @@
public.ecr.aws/falcosecurity/falco,
quay.io/calico/node,
sysdig/sysdig,
sematext_images
sematext_images,
k8s.gcr.io/dns/k8s-dns-node-cache
]
- macro: falco_privileged_containers
@@ -1881,7 +1888,8 @@
aws_eks_image_sensitive_mount or
container.image.repository in (trusted_images) or
container.image.repository in (falco_sensitive_mount_images) or
container.image.repository startswith quay.io/sysdig/)
container.image.repository startswith quay.io/sysdig/ or
container.image.repository=k8scloudprovider/cinder-csi-plugin)
# Add conditions to this macro (probably in a separate file,
# overwriting this macro) to specify additional containers that are
@@ -1899,6 +1907,7 @@
and container.privileged=true
and not falco_privileged_containers
and not user_privileged_containers
and not redhat_image
output: Privileged container started (user=%user.name user_loginuid=%user.loginuid command=%proc.cmdline %container.info image=%container.image.repository:%container.image.tag)
priority: INFO
tags: [container, cis, mitre_privilege_escalation, mitre_lateral_movement]
@@ -2197,9 +2206,6 @@
- list: test_connect_ports
items: [0, 9, 80, 3306]
- macro: do_unexpected_udp_check
condition: (never_true)
- list: expected_udp_ports
items: [53, openvpn_udp_ports, l2tp_udp_ports, statsd_ports, ntp_ports, test_connect_ports]
@@ -2208,7 +2214,8 @@
- rule: Unexpected UDP Traffic
desc: UDP traffic not on port 53 (DNS) or other commonly used ports
condition: (inbound_outbound) and do_unexpected_udp_check and fd.l4proto=udp and not expected_udp_traffic
condition: (inbound_outbound) and fd.l4proto=udp and not expected_udp_traffic
enabled: false
output: >
Unexpected UDP Traffic Seen
(user=%user.name user_loginuid=%user.loginuid command=%proc.cmdline connection=%fd.name proto=%fd.l4proto evt=%evt.type %evt.args container_id=%container.id image=%container.image.repository)
@@ -2391,7 +2398,12 @@
sysdig/sysdig, falcosecurity/falco,
fluent/fluentd-kubernetes-daemonset, prom/prometheus,
ibm_cloud_containers,
public.ecr.aws/falcosecurity/falco)
public.ecr.aws/falcosecurity/falco, velero/velero,
quay.io/jetstack/cert-manager-cainjector, weaveworks/kured,
quay.io/prometheus-operator/prometheus-operator,
k8s.gcr.io/ingress-nginx/kube-webhook-certgen, quay.io/spotahome/redis-operator,
registry.opensource.zalan.do/acid/postgres-operator, registry.opensource.zalan.do/acid/postgres-operator-ui,
rabbitmqoperator/cluster-operator)
or (k8s.ns.name = "kube-system"))
- macro: k8s_api_server
@@ -2445,6 +2457,11 @@
condition: (never_true)
# Container is supposed to be immutable. Package management should be done in building the image.
- macro: pkg_mgmt_in_kube_proxy
condition: >
proc.cmdline startswith "update-alternat"
and container.image.repository = "k8s.gcr.io/kube-proxy"
- rule: Launch Package Management Process in Container
desc: Package management process ran inside container
condition: >
@@ -2454,6 +2471,7 @@
and package_mgmt_procs
and not package_mgmt_ancestor_procs
and not user_known_package_manager_in_container
and not pkg_mgmt_in_kube_proxy
output: >
Package management process launched in container (user=%user.name user_loginuid=%user.loginuid
command=%proc.cmdline container_id=%container.id container_name=%container.name image=%container.image.repository:%container.image.tag)

View File

@@ -261,6 +261,13 @@ print_clean_termination() {
echo
}
print_filename_components() {
echo " - driver name: ${DRIVER_NAME}"
echo " - target identifier: ${TARGET_ID}"
echo " - kernel release: ${KERNEL_RELEASE}"
echo " - kernel version: ${KERNEL_VERSION}"
}
clean_kernel_module() {
echo
echo "================ Cleaning phase ================"
@@ -349,6 +356,8 @@ load_kernel_module() {
get_target_id
local FALCO_KERNEL_MODULE_FILENAME="${DRIVER_NAME}_${TARGET_ID}_${KERNEL_RELEASE}_${KERNEL_VERSION}.ko"
echo "* Filename '${FALCO_KERNEL_MODULE_FILENAME}' is composed of:"
print_filename_components
if [ -f "${HOME}/.falco/${FALCO_KERNEL_MODULE_FILENAME}" ]; then
echo "* Found a prebuilt ${DRIVER_NAME} module at ${HOME}/.falco/${FALCO_KERNEL_MODULE_FILENAME}, loading it"
@@ -493,7 +502,7 @@ load_bpf_probe_compile() {
load_bpf_probe_download() {
local URL
URL=$(echo "${DRIVERS_REPO}/${DRIVER_VERSION}/${BPF_PROBE_FILENAME}" | sed s/+/%2B/g)
URL=$(echo "${DRIVERS_REPO}/${DRIVER_VERSION}/${ARCH}/${BPF_PROBE_FILENAME}" | sed s/+/%2B/g)
echo "* Trying to download a prebuilt eBPF probe from ${URL}"
@@ -504,15 +513,17 @@ load_bpf_probe_download() {
}
load_bpf_probe() {
echo "* Mounting debugfs"
if [ ! -d /sys/kernel/debug/tracing ]; then
echo "* Mounting debugfs"
mount -t debugfs nodev /sys/kernel/debug
fi
get_target_id
BPF_PROBE_FILENAME="${DRIVER_NAME}_${TARGET_ID}_${KERNEL_RELEASE}_${KERNEL_VERSION}.o"
echo "* Filename '${BPF_PROBE_FILENAME}' is composed of:"
print_filename_components
if [ -n "$ENABLE_DOWNLOAD" ]; then
if [ -f "${HOME}/.falco/${BPF_PROBE_FILENAME}" ]; then
@@ -662,7 +673,7 @@ if [ -z "$has_opts" ]; then
fi
if [ -z "$source_only" ]; then
echo "* Running falco-driver-loader for: falco version=${FALCO_VERSION}, driver version=${DRIVER_VERSION}"
echo "* Running falco-driver-loader for: falco version=${FALCO_VERSION}, driver version=${DRIVER_VERSION}, arch=${ARCH}, kernel release=${KERNEL_RELEASE}, kernel version=${KERNEL_VERSION}"
if [ "$(id -u)" != 0 ]; then
>&2 echo "This program must be run as root (or with sudo)"

View File

@@ -77,6 +77,10 @@ class FalcoTest(Test):
else:
self.stderr_not_contains = [self.stderr_not_contains]
self.validate_ok = self.params.get('validate_ok', '*', default='')
self.validate_warnings = self.params.get('validate_warnings', '*', default='')
self.validate_errors = self.params.get('validate_errors', '*', default='')
self.exit_status = self.params.get('exit_status', '*', default=0)
self.should_detect = self.params.get('detect', '*', default=False)
self.check_detection_counts = self.params.get('check_detection_counts', '*', default=True)
@@ -105,6 +109,9 @@ class FalcoTest(Test):
if self.validate_rules_file == False:
self.validate_rules_file = []
else:
# Always enable json output when validating rules
# files. Makes parsing errors/warnings easier
self.json_output = True
if not isinstance(self.validate_rules_file, list):
self.validate_rules_file = [self.validate_rules_file]
@@ -153,13 +160,6 @@ class FalcoTest(Test):
detect_counts[key] = value
self.detect_counts = detect_counts
self.rules_warning = self.params.get(
'rules_warning', '*', default=False)
if self.rules_warning == False:
self.rules_warning = set()
else:
self.rules_warning = set(self.rules_warning)
# Maps from rule name to set of evttypes
self.rules_events = self.params.get('rules_events', '*', default=False)
if self.rules_events == False:
@@ -265,22 +265,6 @@ class FalcoTest(Test):
if self.package != 'None':
self.uninstall_package()
def check_rules_warnings(self, res):
found_warning = set()
for match in re.finditer('Rule ([^:]+): warning \(([^)]+)\):', res.stderr.decode("utf-8")):
rule = match.group(1)
warning = match.group(2)
found_warning.add(rule)
self.log.debug("Expected warning rules: {}".format(self.rules_warning))
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))
def check_rules_events(self, res):
found_events = {}
@@ -376,7 +360,68 @@ class FalcoTest(Test):
return True
def check_json_output(self, res):
def get_validate_json(self, res):
if self.validate_json is None:
# The first line of stdout should be the validation result as json
self.validate_json = json.loads(res.stdout.decode("utf-8").partition('\n')[0])
return self.validate_json
def check_validate_ok(self, res):
if self.validate_ok != '':
vobj = self.get_validate_json(res)
for expected in self.validate_ok:
found = False
for vres in vobj["falco_load_results"]:
if vres["successful"] and os.path.basename(vres["name"]) == expected:
found = True
break
if not found:
self.fail("Validation json did not contain a successful result for file '{}'".format(expected))
def check_validate_warnings(self, res):
if self.validate_warnings != '':
vobj = self.get_validate_json(res)
for warnobj in self.validate_warnings:
found = False
for vres in vobj["falco_load_results"]:
for warning in vres["warnings"]:
if warning["code"] == warnobj["code"]:
if ("message" in warnobj and warning["message"] == warnobj["message"]) or ("message_contains" in warnobj and warnobj["message_contains"] in warning["message"]):
for loc in warning["context"]["locations"]:
if loc["item_type"] == warnobj["item_type"] and loc["item_name"] == warnobj["item_name"]:
found = True
break
if not found:
if "message" in warnobj:
self.fail("Validation json did not contain a warning '{}' for '{}' '{}' with message '{}'".format(
warnobj["code"], warnobj["item_type"], warnobj["item_name"], warnobj["message"]))
else:
self.fail("Validation json did not contain a warning '{}' for '{}' '{}' with message containing '{}'".format(
warnobj["code"], warnobj["item_type"], warnobj["item_name"], warnobj["message_contains"]))
def check_validate_errors(self, res):
if self.validate_errors != '':
vobj = self.get_validate_json(res)
for errobj in self.validate_errors:
found = False
for vres in vobj["falco_load_results"]:
for error in vres["errors"]:
if error["code"] == errobj["code"]:
if ("message" in errobj and error["message"] == errobj["message"]) or ("message_contains" in errobj and errobj["message_contains"] in error["message"]):
for loc in error["context"]["locations"]:
if loc["item_type"] == errobj["item_type"] and loc["item_name"] == errobj["item_name"]:
found = True
break
if not found:
if "message" in errobj:
self.fail("Validation json did not contain a error '{}' for '{}' '{}' with message '{}'".format(
errobj["code"], errobj["item_type"], errobj["item_name"], errobj["message"]))
else:
self.fail("Validation json did not contain a error '{}' for '{}' '{}' with message containing '{}'".format(
errobj["code"], errobj["item_type"], errobj["item_name"], errobj["message_contains"]))
def check_json_event_output(self, res):
if self.json_output:
# Just verify that any lines starting with '{' are valid json objects.
# Doesn't do any deep inspection of the contents.
@@ -578,6 +623,8 @@ class FalcoTest(Test):
# This sets falco_binary_path as a side-effect.
self.install_package()
self.validate_json = None
trace_arg = self.trace_file
if self.trace_file:
@@ -644,18 +691,22 @@ class FalcoTest(Test):
self.error("Falco command \"{}\" exited with unexpected return value {} (!= {})".format(
cmd, res.exit_status, self.exit_status))
self.check_validate_ok(res)
self.check_validate_errors(res)
self.check_validate_warnings(res)
# No need to check any outputs if the falco process exited abnormally.
if res.exit_status != 0:
return
self.check_rules_warnings(res)
if len(self.rules_events) > 0:
self.check_rules_events(res)
if len(self.validate_rules_file) == 0 and self.check_detection_counts:
self.check_detections(res)
if len(self.detect_counts) > 0:
self.check_detections_by_rule(res)
self.check_json_output(res)
if not self.validate_rules_file:
self.check_json_event_output(res)
self.check_outputs()
self.check_output_strictly_contains(res)
self.check_grpc()

View File

@@ -20,22 +20,55 @@ trace_files: !mux
builtin_rules_no_warnings:
detect: False
trace_file: trace_files/empty.scap
rules_warning: False
# The rules_events part of this test was mistakenly disabled when
# generic events (e.g. k8s_audit support) was added (#1715).
# The implementation no longer prints messages of the form:
# "Event types for rule (<RULE>): (<EVENT TYPES>)
# And without that output, none of the checks below rules_events
# are considered.
# XXX/mstemm add it back
test_warnings:
detect: False
trace_file: trace_files/empty.scap
rules_file: rules/falco_rules_warnings.yaml
rules_warning:
- no_evttype
- evttype_not_equals
- leading_not
- not_equals_at_end
- not_at_end
- not_equals_and_not
- leading_in_not_equals_at_evttype
- not_with_evttypes
- not_with_evttypes_addl
validate_rules_file: rules/falco_rules_warnings.yaml
validate_warnings:
- item_type: rule
item_name: no_evttype
code: LOAD_NO_EVTTYPE
message: "Rule matches too many evt.type values. This has a significant performance penalty."
- item_type: rule
item_name: evttype_not_equals
code: LOAD_NO_EVTTYPE
message: "Rule matches too many evt.type values. This has a significant performance penalty."
- item_type: rule
item_name: leading_not
code: LOAD_NO_EVTTYPE
message: "Rule matches too many evt.type values. This has a significant performance penalty."
- item_type: rule
item_name: not_equals_at_end
code: LOAD_NO_EVTTYPE
message: "Rule matches too many evt.type values. This has a significant performance penalty."
- item_type: rule
item_name: not_at_end
code: LOAD_NO_EVTTYPE
message: "Rule matches too many evt.type values. This has a significant performance penalty."
- item_type: rule
item_name: not_equals_and_not
code: LOAD_NO_EVTTYPE
message: "Rule matches too many evt.type values. This has a significant performance penalty."
- item_type: rule
item_name: leading_in_not_equals_at_evttype
code: LOAD_NO_EVTTYPE
message: "Rule matches too many evt.type values. This has a significant performance penalty."
- item_type: rule
item_name: not_with_evttypes
code: LOAD_NO_EVTTYPE
message: "Rule matches too many evt.type values. This has a significant performance penalty."
- item_type: rule
item_name: not_with_evttypes_addl
code: LOAD_NO_EVTTYPE
message: "Rule matches too many evt.type values. This has a significant performance penalty."
rules_events:
- no_warnings: [execve]
- no_evttype: [all]
@@ -251,159 +284,149 @@ trace_files: !mux
invalid_not_yaml:
exit_status: 1
stdout_is: |+
1 errors:
Rules content is not yaml
validate_errors:
- item_type: file
item_name: ""
code: LOAD_ERR_YAML_VALIDATE
message: "Rules content is not yaml"
validate_rules_file:
- rules/invalid_not_yaml.yaml
trace_file: trace_files/cat_write.scap
invalid_not_array:
exit_status: 1
stdout_is: |+
1 errors:
Rules content is not yaml array of objects
validate_errors:
- item_type: file
item_name: ""
code: LOAD_ERR_YAML_VALIDATE
message: "Rules content is not yaml array of objects"
validate_rules_file:
- rules/invalid_not_array.yaml
trace_file: trace_files/cat_write.scap
invalid_array_item_not_object:
exit_status: 1
stdout_is: |+
1 errors:
Unexpected element type. Each element should be a yaml associative array.
---
- foo
---
validate_errors:
- item_type: item
item_name: ""
code: LOAD_ERR_YAML_VALIDATE
message: "Unexpected element type. Each element should be a yaml associative array."
validate_rules_file:
- rules/invalid_array_item_not_object.yaml
trace_file: trace_files/cat_write.scap
invalid_engine_version_not_number:
exit_status: 1
stdout_is: |+
1 errors:
Value of required_engine_version must be a number
---
- required_engine_version: not-a-number
---
validate_errors:
- item_type: required_engine_version
item_name: ""
code: LOAD_ERR_YAML_VALIDATE
message: "Can't decode YAML scalar value"
validate_rules_file:
- rules/invalid_engine_version_not_number.yaml
trace_file: trace_files/cat_write.scap
invalid_yaml_parse_error:
exit_status: 1
validate_errors:
- item_type: file
item_name: ""
code: LOAD_ERR_YAML_PARSE
message: "yaml-cpp: error at line 1, column 11: illegal map value"
validate_rules_file:
- rules/invalid_yaml_parse_error.yaml
trace_file: trace_files/cat_write.scap
invalid_list_without_items:
exit_status: 1
stdout_is: |+
1 errors:
List must have property items
---
- list: bad_list
no_items: foo
---
validate_errors:
- item_type: list
item_name: bad_list
code: LOAD_ERR_YAML_VALIDATE
message: "Item has no mapping for key 'items'"
validate_rules_file:
- rules/invalid_list_without_items.yaml
trace_file: trace_files/cat_write.scap
invalid_macro_without_condition:
exit_status: 1
stdout_is: |+
1 errors:
Macro must have property condition
---
- macro: bad_macro
nope: 1
---
validate_errors:
- item_type: macro
item_name: bad_macro
code: LOAD_ERR_YAML_VALIDATE
message: "Item has no mapping for key 'condition'"
validate_rules_file:
- rules/invalid_macro_without_condition.yaml
trace_file: trace_files/cat_write.scap
invalid_rule_without_output:
exit_status: 1
stdout_is: |+
1 errors:
Rule must have properties 'condition', 'output', 'desc', and 'priority'
---
- rule: no output rule
desc: some desc
condition: evt.type=fork
priority: INFO
---
validate_errors:
- item_type: rule
item_name: no output rule
code: LOAD_ERR_YAML_VALIDATE
message: "Item has no mapping for key 'output'"
validate_rules_file:
- rules/invalid_rule_without_output.yaml
trace_file: trace_files/cat_write.scap
invalid_append_rule_without_condition:
exit_status: 1
stdout_is: |+
1 errors:
Appended rule must have exceptions or condition property
---
- rule: no condition rule
append: true
---
validate_errors:
- item_type: rule
item_name: no condition rule
code: LOAD_ERR_VALIDATE
message: "Appended rule must have exceptions or condition property"
validate_rules_file:
- rules/invalid_append_rule_without_condition.yaml
trace_file: trace_files/cat_write.scap
invalid_append_macro_dangling:
exit_status: 1
stdout_is: |+
1 errors:
Macro dangling append has 'append' key but no macro by that name already exists
---
- macro: dangling append
condition: and evt.type=execve
append: true
---
validate_errors:
- item_type: macro
item_name: dangling append
code: LOAD_ERR_VALIDATE
message: "Macro has 'append' key but no macro by that name already exists"
validate_rules_file:
- rules/invalid_append_macro_dangling.yaml
trace_file: trace_files/cat_write.scap
invalid_list_append_dangling:
exit_status: 1
stdout_is: |+
1 errors:
List my_list has 'append' key but no list by that name already exists
---
- list: my_list
items: [not-cat]
append: true
---
validate_errors:
- item_type: list
item_name: my_list
code: LOAD_ERR_VALIDATE
message: "List has 'append' key but no list by that name already exists"
validate_rules_file:
- rules/list_append_failure.yaml
trace_file: trace_files/cat_write.scap
invalid_rule_append_dangling:
exit_status: 1
stdout_is: |+
1 errors:
Rule my_rule has 'append' key but no rule by that name already exists
---
- rule: my_rule
condition: evt.type=open
append: true
---
validate_errors:
- item_type: rule
item_name: my_rule
code: LOAD_ERR_VALIDATE
message: "Rule has 'append' key but no rule by that name already exists"
validate_rules_file:
- rules/rule_append_failure.yaml
trace_file: trace_files/cat_write.scap
invalid_overwrite_macro:
exit_status: 1
stdout_contains: |+
.*invalid_base_macro.yaml: Ok
.*invalid_overwrite_macro.yaml: 1 errors:
Compilation error when compiling "foo": Undefined macro 'foo' used in filter.
---
- macro: some macro
condition: foo
append: false
---
validate_ok: [invalid_base_macro.yaml]
validate_errors:
- item_type: macro
item_name: some macro
code: LOAD_ERR_VALIDATE
message: "Undefined macro 'foo' used in filter."
validate_warnings:
- item_type: macro
item_name: some macro
code: LOAD_UNUSED_MACRO
message: "Macro not referred to by any other rule/macro"
validate_rules_file:
- rules/invalid_base_macro.yaml
- rules/invalid_overwrite_macro.yaml
@@ -411,18 +434,17 @@ trace_files: !mux
invalid_append_macro:
exit_status: 1
stdout_contains: |+
.*invalid_base_macro.yaml: Ok
.*invalid_append_macro.yaml: 1 errors:
Compilation error when compiling "evt.type=execve foo": 17: unexpected token after 'execve', expecting 'or', 'and'
---
- macro: some macro
condition: evt.type=execve
- macro: some macro
condition: foo
append: true
---
validate_ok: [invalid_base_macro.yaml]
validate_errors:
- item_type: macro
item_name: some macro
code: LOAD_ERR_COMPILE_CONDITION
message: "unexpected token after 'execve', expecting 'or', 'and'"
validate_warnings:
- item_type: macro
item_name: some macro
code: LOAD_UNUSED_MACRO
message: "Macro not referred to by any other rule/macro"
validate_rules_file:
- rules/invalid_base_macro.yaml
- rules/invalid_append_macro.yaml
@@ -430,49 +452,39 @@ trace_files: !mux
invalid_overwrite_macro_multiple_docs:
exit_status: 1
stdout_is: |+
1 errors:
Compilation error when compiling "foo": Undefined macro 'foo' used in filter.
---
- macro: some macro
condition: foo
append: false
---
validate_errors:
- item_type: macro
item_name: some macro
code: LOAD_ERR_VALIDATE
message: "Undefined macro 'foo' used in filter."
validate_warnings:
- item_type: macro
item_name: some macro
code: LOAD_UNUSED_MACRO
message: "Macro not referred to by any other rule/macro"
validate_rules_file:
- rules/invalid_overwrite_macro_multiple_docs.yaml
trace_file: trace_files/cat_write.scap
invalid_append_macro_multiple_docs:
exit_status: 1
stdout_is: |+
1 errors:
Compilation error when compiling "evt.type=execve foo": 17: unexpected token after 'execve', expecting 'or', 'and'
---
- macro: some macro
condition: evt.type=execve
- macro: some macro
condition: foo
append: true
---
validate_errors:
- item_type: macro
item_name: some macro
code: LOAD_ERR_COMPILE_CONDITION
message: "unexpected token after 'execve', expecting 'or', 'and'"
validate_rules_file:
- rules/invalid_append_macro_multiple_docs.yaml
trace_file: trace_files/cat_write.scap
invalid_overwrite_rule:
exit_status: 1
stdout_contains: |+
.*invalid_base_rule.yaml: Ok
.*invalid_overwrite_rule.yaml: 1 errors:
Undefined macro 'bar' used in filter.
---
- rule: some rule
desc: some desc
condition: bar
output: some output
priority: INFO
append: false
---
validate_ok: [invalid_base_rule.yaml]
validate_errors:
- item_type: rule
item_name: some rule
code: LOAD_ERR_VALIDATE
message: "Undefined macro 'bar' used in filter."
validate_rules_file:
- rules/invalid_base_rule.yaml
- rules/invalid_overwrite_rule.yaml
@@ -480,24 +492,12 @@ trace_files: !mux
invalid_append_rule:
exit_status: 1
stdout_contains: |+
.*invalid_base_rule.yaml: Ok
.*invalid_append_rule.yaml: 1 errors:
Compilation error when compiling "evt.type=open bar": 15: unexpected token after 'open', expecting 'or', 'and'
---
- rule: some rule
desc: some desc
condition: evt.type=open
output: some output
priority: INFO
- rule: some rule
desc: some desc
condition: bar
output: some output
priority: INFO
append: true
---
validate_ok: [invalid_base_rule.yaml]
validate_errors:
- item_type: rule
item_name: some rule
code: LOAD_ERR_COMPILE_CONDITION
message: "unexpected token after 'open', expecting 'or', 'and'"
validate_rules_file:
- rules/invalid_base_rule.yaml
- rules/invalid_append_rule.yaml
@@ -505,96 +505,66 @@ trace_files: !mux
invalid_overwrite_rule_multiple_docs:
exit_status: 1
stdout_is: |+
1 errors:
Undefined macro 'bar' used in filter.
---
- rule: some rule
desc: some desc
condition: bar
output: some output
priority: INFO
append: false
---
validate_errors:
- item_type: rule
item_name: some rule
code: LOAD_ERR_VALIDATE
message: "Undefined macro 'bar' used in filter."
validate_rules_file:
- rules/invalid_overwrite_rule_multiple_docs.yaml
trace_file: trace_files/cat_write.scap
invalid_append_rule_multiple_docs:
exit_status: 1
stdout_contains: |+
Compilation error when compiling "evt.type=open bar": 15: unexpected token after 'open', expecting 'or', 'and'
---
- rule: some rule
desc: some desc
condition: evt.type=open
output: some output
priority: INFO
- rule: some rule
desc: some desc
condition: bar
output: some output
priority: INFO
append: true
---
validate_errors:
- item_type: rule
item_name: some rule
code: LOAD_ERR_COMPILE_CONDITION
message: "unexpected token after 'open', expecting 'or', 'and'"
validate_rules_file:
- rules/invalid_append_rule_multiple_docs.yaml
trace_file: trace_files/cat_write.scap
invalid_missing_rule_name:
exit_status: 1
stdout_is: |+
1 errors:
Rule name is empty
---
- rule:
desc: some desc
condition: evt.type=execve
output: some output
---
validate_errors:
- item_type: rule
item_name: ""
code: LOAD_ERR_YAML_VALIDATE
message: "Mapping for key 'rule' is empty"
validate_rules_file:
- rules/invalid_missing_rule_name.yaml
trace_file: trace_files/cat_write.scap
invalid_missing_list_name:
exit_status: 1
stdout_is: |+
1 errors:
List name is empty
---
- list:
items: [foo]
---
validate_errors:
- item_type: list
item_name: ""
code: LOAD_ERR_YAML_VALIDATE
message: "Mapping for key 'list' is empty"
validate_rules_file:
- rules/invalid_missing_list_name.yaml
trace_file: trace_files/cat_write.scap
invalid_missing_macro_name:
exit_status: 1
stdout_is: |+
1 errors:
Macro name is empty
---
- macro:
condition: evt.type=execve
---
validate_errors:
- item_type: macro
item_name: ""
code: LOAD_ERR_YAML_VALIDATE
message: "Mapping for key 'macro' is empty"
validate_rules_file:
- rules/invalid_missing_macro_name.yaml
trace_file: trace_files/cat_write.scap
invalid_rule_output:
exit_status: 1
stdout_is: |+
1 errors:
Invalid output format 'An open was seen %not_a_real_field': 'invalid formatting token not_a_real_field'
---
- rule: rule_with_invalid_output
desc: A rule with an invalid output field
condition: evt.type=open
output: "An open was seen %not_a_real_field"
priority: WARNING
---
validate_errors:
- item_type: rule
item_name: rule_with_invalid_output
code: LOAD_ERR_COMPILE_OUTPUT
message: "invalid formatting token not_a_real_field"
validate_rules_file:
- rules/invalid_rule_output.yaml
trace_file: trace_files/cat_write.scap
@@ -622,13 +592,13 @@ trace_files: !mux
rules_file:
- rules/single_rule_enabled_flag.yaml
trace_file: trace_files/cat_write.scap
disabled_rule_using_false_enabled_flag_only:
detect: False
rules_file:
- rules/disabled_rule_using_enabled_flag_only.yaml
trace_file: trace_files/cat_write.scap
enabled_rule_using_false_enabled_flag_only:
detect: True
detect_level: WARNING
@@ -1025,13 +995,6 @@ trace_files: !mux
- open_12: 0
- open_13: 0
list_append_failure:
exit_status: 1
stderr_contains: "List my_list has 'append' key but no list by that name already exists"
rules_file:
- rules/list_append_failure.yaml
trace_file: trace_files/cat_write.scap
list_append:
detect: True
detect_level: WARNING
@@ -1045,13 +1008,6 @@ trace_files: !mux
- rules/list_append_false.yaml
trace_file: trace_files/cat_write.scap
macro_append_failure:
exit_status: 1
stderr_contains: "Macro my_macro has 'append' key but no macro by that name already exists"
rules_file:
- rules/macro_append_failure.yaml
trace_file: trace_files/cat_write.scap
macro_append:
detect: True
detect_level: WARNING
@@ -1065,13 +1021,6 @@ trace_files: !mux
- rules/macro_append_false.yaml
trace_file: trace_files/cat_write.scap
rule_append_failure:
exit_status: 1
stderr_contains: "Rule my_rule has 'append' key but no rule by that name already exists"
rules_file:
- rules/rule_append_failure.yaml
trace_file: trace_files/cat_write.scap
rule_append_skipped:
detect: False
priority: ERROR
@@ -1152,10 +1101,18 @@ trace_files: !mux
dev_null: 0
trace_file: trace_files/cat_write.scap
skip_unknown_noevt:
validate_skip_unknown_noevt:
validate_warnings:
- item_type: rule
item_name: "Contains Unknown Event And Skipping"
code: LOAD_UNKNOWN_FIELD
message: "filter_check called with nonexistent field proc.nobody"
validate_rules_file:
- rules/skip_unknown_evt.yaml
trace_file: trace_files/cat_write.scap
detect_skip_unknown_noevt:
detect: False
rules_warning:
- Contains Unknown Event And Skipping
rules_file:
- rules/skip_unknown_evt.yaml
trace_file: trace_files/cat_write.scap
@@ -1168,41 +1125,34 @@ trace_files: !mux
skip_unknown_error:
exit_status: 1
stderr_contains: |+
Could not load rules file.*skip_unknown_error.yaml: 1 errors:
Rule Contains Unknown Event And Not Skipping: error filter_check called with nonexistent field proc.nobody
---
- rule: Contains Unknown Event And Not Skipping
desc: Contains an unknown event
condition: proc.nobody=cat
output: Never
skip-if-unknown-filter: false
priority: INFO
---
rules_file:
validate_errors:
- item_type: rule
item_name: "Contains Unknown Event And Not Skipping"
code: LOAD_ERR_COMPILE_CONDITION
message: "filter_check called with nonexistent field proc.nobody"
validate_rules_file:
- rules/skip_unknown_error.yaml
trace_file: trace_files/cat_write.scap
skip_unknown_unspec_error:
exit_status: 1
stderr_contains: |+
Could not load rules file .*skip_unknown_unspec.yaml: 1 errors:
Rule Contains Unknown Event And Unspecified: error filter_check called with nonexistent field proc.nobody
---
- rule: Contains Unknown Event And Unspecified
desc: Contains an unknown event
condition: proc.nobody=cat
output: Never
priority: INFO
---
rules_file:
validate_errors:
- item_type: rule
item_name: "Contains Unknown Event And Unspecified"
code: LOAD_ERR_COMPILE_CONDITION
message: "filter_check called with nonexistent field proc.nobody"
validate_rules_file:
- rules/skip_unknown_unspec.yaml
trace_file: trace_files/cat_write.scap
engine_version_mismatch:
exit_status: 1
stderr_contains: Rules require engine version 9999999, but engine version is
rules_file:
validate_errors:
- item_type: required_engine_version
item_name: ""
code: LOAD_ERR_VALIDATE
message_contains: "Rules require engine version 9999999, but engine version is"
validate_rules_file:
- rules/engine_version_mismatch.yaml
trace_file: trace_files/cat_write.scap

View File

@@ -20,175 +20,99 @@ trace_files: !mux
rule_exception_no_fields:
exit_status: 1
stdout_is: |+
1 errors:
Rule exception item ex1: must have fields property with a list of fields
---
- rule: My Rule
desc: Some desc
condition: evt.type=open and proc.name=cat
output: Some output
exceptions:
- name: ex1
priority: error
---
validate_errors:
- item_type: exception
item_name: ex1
code: LOAD_ERR_YAML_VALIDATE
message: "Item has no mapping for key 'fields'"
validate_rules_file:
- rules/exceptions/item_no_fields.yaml
trace_file: trace_files/cat_write.scap
rule_exception_no_name:
exit_status: 1
stdout_is: |+
1 errors:
Rule exception item must have name property
---
- rule: My Rule
desc: Some desc
condition: evt.type=open and proc.name=cat
output: Some output
exceptions:
- fields: [proc.name, fd.filename]
priority: error
---
validate_errors:
- item_type: exception
item_name: ""
code: LOAD_ERR_YAML_VALIDATE
message: "Item has no mapping for key 'name'"
validate_rules_file:
- rules/exceptions/item_no_name.yaml
trace_file: trace_files/cat_write.scap
rule_exception_append_no_name:
exit_status: 1
stdout_is: |+
1 errors:
Rule exception item must have name property
---
- rule: My Rule
exceptions:
- values:
- [nginx, /tmp/foo]
append: true
---
validate_errors:
- item_type: exception
item_name: ""
code: LOAD_ERR_YAML_VALIDATE
message: "Item has no mapping for key 'name'"
validate_rules_file:
- rules/exceptions/append_item_no_name.yaml
trace_file: trace_files/cat_write.scap
rule_exception_unknown_fields:
exit_status: 1
stdout_is: |+
1 errors:
Rule exception item ex1: field name not.exist is not a supported filter field
---
- rule: My Rule
desc: Some desc
condition: evt.type=open and proc.name=cat
output: Some output
exceptions:
- name: ex1
fields: [not.exist]
priority: error
---
validate_errors:
- item_type: exception
item_name: ex1
code: LOAD_ERR_VALIDATE
message: "'not.exist' is not a supported filter field"
validate_rules_file:
- rules/exceptions/item_unknown_fields.yaml
trace_file: trace_files/cat_write.scap
rule_exception_comps_fields_len_mismatch:
exit_status: 1
stdout_is: |+
1 errors:
Rule exception item ex1: fields and comps lists must have equal length
---
- rule: My Rule
desc: Some desc
condition: evt.type=open and proc.name=cat
output: Some output
exceptions:
- name: ex1
fields: [proc.name, fd.filename]
comps: [=]
priority: error
---
validate_errors:
- item_type: exception
item_name: ex1
code: LOAD_ERR_VALIDATE
message: "Fields and comps lists must have equal length"
validate_rules_file:
- rules/exceptions/item_comps_fields_len_mismatch.yaml
trace_file: trace_files/cat_write.scap
rule_exception_unknown_comp:
exit_status: 1
stdout_is: |+
1 errors:
Rule exception item ex1: comparison operator no-comp is not a supported comparison operator
---
- rule: My Rule
desc: Some desc
condition: evt.type=open and proc.name=cat
output: Some output
exceptions:
- name: ex1
fields: [proc.name, fd.filename]
comps: [=, no-comp]
priority: error
---
validate_errors:
- item_type: exception
item_name: ex1
code: LOAD_ERR_VALIDATE
message: "'no-comp' is not a supported comparison operator"
validate_rules_file:
- rules/exceptions/item_unknown_comp.yaml
trace_file: trace_files/cat_write.scap
rule_exception_fields_values_len_mismatch:
exit_status: 1
stdout_is: |+
1 errors:
Exception item ex1: fields and values lists must have equal length
---
- rule: My Rule
desc: Some desc
condition: evt.type=open and proc.name=cat
output: Some output
exceptions:
- name: ex1
fields: [proc.name, fd.filename]
values:
- [nginx]
priority: error
---
validate_errors:
- item_type: exception
item_name: ex1
code: LOAD_ERR_VALIDATE
message: "Fields and values lists must have equal length"
validate_rules_file:
- rules/exceptions/item_fields_values_len_mismatch.yaml
trace_file: trace_files/cat_write.scap
rule_exception_append_fields_values_len_mismatch:
exit_status: 1
stdout_is: |+
1 errors:
Exception item ex1: fields and values lists must have equal length
---
- rule: My Rule
desc: Some desc
condition: evt.type=open and proc.name=cat
output: Some output
exceptions:
- name: ex1
fields: [proc.name, fd.filename]
priority: error
- rule: My Rule
exceptions:
- name: ex1
values:
- [nginx]
append: true
---
validate_errors:
- item_type: exception
item_name: ex1
code: LOAD_ERR_VALIDATE
message: "Fields and values lists must have equal length"
validate_rules_file:
- rules/exceptions/append_item_fields_values_len_mismatch.yaml
trace_file: trace_files/cat_write.scap
rule_exception_append_item_not_in_rule:
exit_status: 1
stdout_is: |+
1 errors:
Rule exception new item ex2: must have fields property with a list of fields
---
- rule: My Rule
exceptions:
- name: ex2
values:
- [apache, /tmp]
append: true
---
validate_errors:
- item_type: exception
item_name: ex2
code: LOAD_ERR_VALIDATE
message: "Rule exception must have fields property with a list of fields"
validate_rules_file:
- rules/exceptions/append_item_not_in_rule.yaml
trace_file: trace_files/cat_write.scap
@@ -325,7 +249,7 @@ trace_files: !mux
rules_file:
- rules/exceptions/rule_exception_new_single_field_append.yaml
trace_file: trace_files/cat_write.scap
rule_exception_new_second_field_append:
detect: False
detect_level: WARNING
@@ -335,18 +259,11 @@ trace_files: !mux
rule_exception_new_append_no_field:
exit_status: 1
stdout_is: |+
1 errors:
Rule exception new item proc_cmdline: must have fields property with a list of fields
---
- rule: Open From Cat
exceptions:
- name: proc_cmdline
comps: in
values:
- "cat /dev/null"
append: true
---
validate_errors:
- item_type: exception
item_name: proc_cmdline
code: LOAD_ERR_VALIDATE
message: "Rule exception must have fields property with a list of fields"
validate_rules_file:
- rules/exceptions/rule_exception_new_no_field_append.yaml
trace_file: trace_files/cat_write.scap

View File

@@ -75,7 +75,7 @@ trace_files: !mux
incompat_plugin_api:
exit_status: 1
stderr_contains: "Plugin required API version '10000000.0.0' is not supported by the plugin API version of the framework '.*'"
stderr_contains: "plugin required API version '10000000.0.0' not compatible with the framework's API version '.*'"
conf_file: BUILD_DIR/test/confs/plugins/incompatible_plugin_api.yaml
rules_file:
- rules/plugins/cloudtrail_create_instances.yaml
@@ -89,27 +89,30 @@ trace_files: !mux
wrong_plugin_path:
exit_status: 1
stderr_contains: "error loading plugin.*No such file or directory. Exiting"
stderr_contains: "cannot load plugin.*No such file or directory"
conf_file: BUILD_DIR/test/confs/plugins/wrong_plugin_path.yaml
rules_file:
- rules/plugins/cloudtrail_incompat_plugin_version.yaml
no_plugins_unknown_source:
detect: False
rules_file:
exit_status: 0
validate_warnings:
- item_type: rule
item_name: Cloudtrail Create Instance
code: LOAD_UNKNOWN_SOURCE
message: "Unknown source aws_cloudtrail, skipping"
validate_rules_file:
- rules/plugins/cloudtrail_create_instances.yaml
trace_file: trace_files/empty.scap
rules_warning:
- Cloudtrail Create Instance
stderr_contains: "Rule Cloudtrail Create Instance: warning .unknown-source.: unknown source aws_cloudtrail, skipping"
no_plugins_unknown_source_rule_exception:
detect: False
rules_file:
exit_status: 0
validate_warnings:
- item_type: rule
item_name: Cloudtrail Create Instance
code: LOAD_UNKNOWN_SOURCE
message: "Unknown source aws_cloudtrail, skipping"
validate_rules_file:
- rules/plugins/cloudtrail_create_instances_exceptions.yaml
trace_file: trace_files/empty.scap
rules_warning:
- Cloudtrail Create Instance
stderr_contains: "Rule Cloudtrail Create Instance: warning .unknown-source.: unknown source aws_cloudtrail, skipping"

View File

@@ -30,6 +30,7 @@ traces: !mux
container-privileged:
trace_file: traces-positive/container-privileged.scap
all_events: True
detect: True
detect_level: INFO
detect_counts:
@@ -37,6 +38,7 @@ traces: !mux
container-sensitive-mount:
trace_file: traces-positive/container-sensitive-mount.scap
all_events: True
detect: True
detect_level: INFO
detect_counts:
@@ -51,6 +53,7 @@ traces: !mux
db-program-spawned-process:
trace_file: traces-positive/db-program-spawned-process.scap
all_events: True
detect: True
detect_level: NOTICE
detect_counts:
@@ -132,6 +135,7 @@ traces: !mux
system-user-interactive:
trace_file: traces-positive/system-user-interactive.scap
all_events: True
detect: True
detect_level: INFO
detect_counts:
@@ -139,6 +143,7 @@ traces: !mux
user-mgmt-binaries:
trace_file: traces-positive/user-mgmt-binaries.scap
all_events: True
detect: True
detect_level: NOTICE
detect_counts:
@@ -169,6 +174,7 @@ traces: !mux
# When a new version of the scap files is generated this should then become "traces-positive"
docker-compose:
trace_file: traces-negative/docker-compose.scap
all_events: True
detect: True
detect_level: NOTICE
detect_counts:

View File

@@ -1,19 +0,0 @@
#
# 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.
#
- macro: my_macro
condition: proc.name=not-cat
append: true

View File

@@ -1,25 +0,0 @@
#!/usr/bin/env bash
#
# 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.
#
# Run sysdig excluding all events that aren't used by Falco and also
# excluding other high-volume events that aren't essential. This
# results in smaller trace files.
# The remaining arguments are taken from the command line.
exec sudo sysdig not evt.type in '(mprotect,brk,mq_timedreceive,mq_receive,mq_timedsend,mq_send,getrusage,procinfo,rt_sigprocmask,rt_sigaction,ioctl,clock_getres,clock_gettime,clock_nanosleep,clock_settime,close,epoll_create,epoll_create1,epoll_ctl,epoll_pwait,epoll_wait,eventfd,fcntl,fcntl64,fstat,fstat64,fstatat64,fstatfs,fstatfs64,futex,getitimer,gettimeofday,ioprio_get,ioprio_set,llseek,lseek,lstat,lstat64,mmap,mmap2,munmap,nanosleep,poll,ppoll,pread,pread64,preadv,procinfo,pselect6,pwrite,pwrite64,pwritev,read,readv,recv,recvfrom,recvmmsg,recvmsg,sched_yield,select,send,sendfile,sendfile64,sendmmsg,sendmsg,sendto,setitimer,settimeofday,shutdown,splice,stat,stat64,statfs,statfs64,switch,tee,timer_create,timer_delete,timerfd_create,timerfd_gettime,timerfd_settime,timer_getoverrun,timer_gettime,timer_settime,wait4,write,writev) and user.name!=ec2-user' "$@"

View File

@@ -57,12 +57,14 @@ ast::expr* compile(const string &fltstr)
TEST_CASE("Should find event types from filter", "[rule_loader]")
{
set<uint16_t> openat_only{
PPME_SYSCALL_OPENAT_E, PPME_SYSCALL_OPENAT_X,
PPME_SYSCALL_OPENAT_2_E, PPME_SYSCALL_OPENAT_2_X };
set<uint16_t> close_only{
PPME_SYSCALL_CLOSE_E, PPME_SYSCALL_CLOSE_X };
set<uint16_t> openat_close{
PPME_SYSCALL_OPENAT_E, PPME_SYSCALL_OPENAT_X,
PPME_SYSCALL_OPENAT_2_E, PPME_SYSCALL_OPENAT_2_X,
PPME_SYSCALL_CLOSE_E, PPME_SYSCALL_CLOSE_X };
@@ -73,9 +75,8 @@ TEST_CASE("Should find event types from filter", "[rule_loader]")
set<uint16_t> no_events;
for(uint32_t i = 2; i < PPM_EVENT_MAX; i++)
{
// Skip "old" event versions that have been replaced
// by newer event versions, or events that are unused.
if(g_infotables.m_event_info[i].flags & (EF_OLD_VERSION | EF_UNUSED))
// Skip events that are unused.
if(g_infotables.m_event_info[i].flags & EF_UNUSED)
{
continue;
}
@@ -231,4 +232,4 @@ TEST_CASE("Should find event types from filter", "[rule_loader]")
auto f = compile("not (not evt.type=openat)");
compare_evttypes(f, openat_only);
}
}
}

View File

@@ -19,7 +19,7 @@ limitations under the License.
static bool warns(const std::string& condition)
{
std::set<std::string> w;
std::set<falco::load_result::warning_code> w;
auto ast = libsinsp::filter::parser(condition).parse();
filter_warning_resolver().run(ast, w);
delete ast;

View File

@@ -13,6 +13,7 @@
set(FALCO_ENGINE_SOURCE_FILES
falco_common.cpp
falco_engine.cpp
falco_load_result.cpp
falco_utils.cpp
json_evt.cpp
evttype_index_ruleset.cpp

View File

@@ -18,6 +18,7 @@ limitations under the License.
#include <unistd.h>
#include <string>
#include <fstream>
#include <utility>
#include <sinsp.h>
#include <plugin.h>
@@ -36,6 +37,7 @@ limitations under the License.
const std::string falco_engine::s_default_ruleset = "falco-default-ruleset";
using namespace std;
using namespace falco;
falco_engine::falco_engine(bool seed_rng)
: m_next_ruleset_id(0),
@@ -165,80 +167,89 @@ void falco_engine::list_fields(std::string &source, bool verbose, bool names_onl
void falco_engine::load_rules(const string &rules_content, bool verbose, bool all_events)
{
uint64_t dummy;
static const std::string no_name = "N/A";
return load_rules(rules_content, verbose, all_events, dummy);
std::unique_ptr<load_result> res = load_rules(rules_content, no_name);
if(verbose)
{
// Here, verbose controls whether to additionally
// "log" e.g. print to stderr. What's logged is always
// non-verbose so it fits on a single line.
// todo(jasondellaluce): introduce a logging callback in Falco
fprintf(stderr, "%s\n", res->as_string(false).c_str());
}
if(!res->successful())
{
// The output here is always the full e.g. "verbose" output.
throw falco_exception(res->as_string(true).c_str());
}
}
void falco_engine::load_rules(const string &rules_content, bool verbose, bool all_events, uint64_t &required_engine_version)
std::unique_ptr<load_result> falco_engine::load_rules(const std::string &rules_content, const std::string &name)
{
rule_loader::configuration cfg(rules_content, m_sources);
rule_loader::configuration cfg(rules_content, m_sources, name);
cfg.min_priority = m_min_priority;
cfg.output_extra = m_extra;
cfg.replace_output_container_info = m_replace_container_info;
cfg.default_ruleset_id = m_default_ruleset_id;
std::ostringstream os;
rule_reader reader;
bool success = reader.load(cfg, m_rule_loader);
if (success)
if (reader.load(cfg, m_rule_loader))
{
for (auto &src : m_sources)
{
src.ruleset = src.ruleset_factory->new_ruleset();
}
m_rules.clear();
success = m_rule_loader.compile(cfg, m_rules);
}
if (!cfg.errors.empty())
{
os << cfg.errors.size() << " errors:" << std::endl;
for(auto &err : cfg.errors)
{
os << err << std::endl;
}
}
if (!cfg.warnings.empty())
{
os << cfg.warnings.size() << " warnings:" << std::endl;
for(auto &warn : cfg.warnings)
{
os << warn << std::endl;
}
}
if(!success)
{
throw falco_exception(os.str());
}
if (verbose && os.str() != "") {
// todo(jasondellaluce): introduce a logging callback in Falco
fprintf(stderr, "When reading rules content: %s", os.str().c_str());
m_rule_loader.compile(cfg, m_rules);
}
return std::move(cfg.res);
}
void falco_engine::load_rules_file(const string &rules_filename, bool verbose, bool all_events)
void falco_engine::load_rules_file(const std::string &rules_filename, bool verbose, bool all_events)
{
uint64_t dummy;
std::unique_ptr<load_result> res = load_rules_file(rules_filename);
return load_rules_file(rules_filename, verbose, all_events, dummy);
if(verbose)
{
// Here, verbose controls whether to additionally
// "log" e.g. print to stderr. What's logged is always
// non-verbose so it fits on a single line.
// todo(jasondellaluce): introduce a logging callback in Falco
fprintf(stderr, "%s\n", res->as_string(false).c_str());
}
if(!res->successful())
{
// The output here is always the full e.g. "verbose" output.
throw falco_exception(res->as_string(true).c_str());
}
}
void falco_engine::load_rules_file(const string &rules_filename, bool verbose, bool all_events, uint64_t &required_engine_version)
std::unique_ptr<load_result> falco_engine::load_rules_file(const string &rules_filename)
{
ifstream is;
is.open(rules_filename);
if (!is.is_open())
{
throw falco_exception("Could not open rules filename " +
rules_filename + " " +
"for reading");
rule_loader::context ctx(rules_filename);
std::string empty;
std::unique_ptr<rule_loader::result> res(new rule_loader::result(rules_filename));
res->add_error(load_result::LOAD_ERR_FILE_READ, "Could not open for reading.", ctx, empty);
return std::move(res);
}
string rules_content((istreambuf_iterator<char>(is)),
istreambuf_iterator<char>());
load_rules(rules_content, verbose, all_events, required_engine_version);
return load_rules(rules_content, rules_filename);
}
void falco_engine::enable_rule(const string &substring, bool enabled, const string &ruleset)
@@ -339,7 +350,7 @@ unique_ptr<falco_engine::rule_result> falco_engine::process_event(std::size_t so
{
return unique_ptr<struct rule_result>();
}
unique_ptr<struct rule_result> res(new rule_result());
res->evt = ev;
res->rule = rule.name;
@@ -441,8 +452,8 @@ bool falco_engine::check_plugin_requirements(
if (!plugin_version.check(req_version))
{
err = "Plugin '" + plugin.name
+ "' version '" + plugin.version
+ "' is not compatible with required plugin version '"
+ "' version '" + plugin.version
+ "' is not compatible with required plugin version '"
+ reqver + "'";
return false;
}

View File

@@ -34,6 +34,7 @@ limitations under the License.
#include "stats_manager.h"
#include "falco_common.h"
#include "falco_source.h"
#include "falco_load_result.h"
//
// This class acts as the primary interface between a program and the
@@ -64,11 +65,10 @@ public:
void load_rules(const std::string &rules_content, bool verbose, bool all_events);
//
// Identical to above, but also returns the required engine version for the file/content.
// (If no required engine version is specified, returns 0).
//
void load_rules_file(const std::string &rules_filename, bool verbose, bool all_events, uint64_t &required_engine_version);
void load_rules(const std::string &rules_content, bool verbose, bool all_events, uint64_t &required_engine_version);
// Identical to above, but returns a result object instead of
// throwing exceptions on error.
std::unique_ptr<falco::load_result> load_rules_file(const std::string &rules_filename);
std::unique_ptr<falco::load_result> load_rules(const std::string &rules_content, const std::string &name);
//
// Enable/Disable any rules matching the provided substring.
@@ -145,7 +145,7 @@ public:
// of all output expressions. You can also choose to replace
// %container.info with the extra information or add it to the
// end of the expression. This is used in open source falco to
// add k8s/mesos/container information to outputs when
// add k8s/container information to outputs when
// available.
//
void set_extra(string &extra, bool replace_container_info);
@@ -188,7 +188,7 @@ public:
std::size_t add_source(const std::string &source,
std::shared_ptr<gen_event_filter_factory> filter_factory,
std::shared_ptr<gen_event_formatter_factory> formatter_factory);
//
// Equivalent to above, but allows specifying a ruleset factory
// for the newly added source.

View File

@@ -16,9 +16,9 @@ limitations under the License.
// The version of rules/filter fields/etc supported by this Falco
// engine.
#define FALCO_ENGINE_VERSION (13)
#define FALCO_ENGINE_VERSION (14)
// This is the result of running "falco --list -N | sha256sum" and
// represents the fields supported by this version of Falco. It's used
// at build time to detect a changed set of fields.
#define FALCO_FIELDS_CHECKSUM "94290ff98e5affc85b2287b09a3f4054918f14e90db1ac4bfd6d5ce4e910329c"
#define FALCO_FIELDS_CHECKSUM "674c6cf2bc1c105038c8676f018fa3d1431d86597df428453441f5d859cad284"

View File

@@ -0,0 +1,104 @@
/*
Copyright (C) 2022 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 "falco_load_result.h"
static const std::string error_codes[] = {
"LOAD_ERR_FILE_READ",
"LOAD_ERR_YAML_PARSE",
"LOAD_ERR_YAML_VALIDATE",
"LOAD_ERR_COMPILE_CONDITION",
"LOAD_ERR_COMPILE_OUTPUT",
"LOAD_ERR_VALIDATE"
};
const std::string& falco::load_result::error_code_str(error_code ec)
{
return error_codes[ec];
}
static const std::string error_strings[] = {
"File read error",
"YAML parse error",
"Error validating internal structure of YAML file",
"Error compiling condition",
"Error compiling output",
"Error validating rule/macro/list/exception objects"
};
const std::string& falco::load_result::error_str(error_code ec)
{
return error_strings[ec];
}
static const std::string error_descs[] = {
"This occurs when falco can not read a given file. Check permissions and whether the file exists.",
"This occurs when the rules content is not valid YAML.",
"This occurs when the internal structure of the YAML file is incorrect. Examples include not consisting of a sequence of maps, a given rule/macro/list item not having required keys, values not having the right type (e.g. the items property of a list not being a sequence), etc.",
"This occurs when a condition string can not be compiled to a filter object.",
"This occurs when an output string can not be compiled to an output object.",
"This occurs when a rule/macro/list item is incorrect. Examples include a condition field referring to an undefined macro, falco engine/plugin version mismatches, items with append without any existing item, exception fields/comps having different lengths, etc."
};
const std::string& falco::load_result::error_desc(error_code ec)
{
return error_strings[ec];
}
static const std::string warning_codes[] = {
"LOAD_UNKNOWN_SOURCE",
"LOAD_UNSAFE_NA_CHECK",
"LOAD_NO_EVTTYPE",
"LOAD_UNKNOWN_FIELD",
"LOAD_UNUSED_MACRO",
"LOAD_UNUSED_LIST",
"LOAD_UNKNOWN_ITEM"
};
const std::string& falco::load_result::warning_code_str(warning_code wc)
{
return warning_codes[wc];
}
static const std::string warning_strings[] = {
"Unknown event source",
"Unsafe <NA> comparison in condition",
"Condition has no event-type restriction",
"Unknown field in condition",
"Unused macro",
"Unused list",
"Unknown rules file item"
};
const std::string& falco::load_result::warning_str(warning_code wc)
{
return warning_strings[wc];
}
static const std::string warning_descs[] = {
"A rule has a unknown event source. This can occur when reading rules content without having a corresponding plugin loaded, etc. The rule will be silently ignored.",
"Comparing a field value with <NA> is unsafe and can lead to unpredictable behavior of the rule condition. If you need to check for the existence of a field, consider using the 'exists' operator instead.",
"A rule condition matches too many evt.type values. This has a significant performance penalty. Make the condition more specific by adding an evt.type field or further restricting the number of evt.type values in the condition.",
"A rule condition refers to a field that does not exist. This is normally an error, but if a rule has a skip-if-unknown-filter property, the error is downgraded to a warning.",
"A macro is defined in the rules content but is not used by any other macro or rule.",
"A list is defined in the rules content but is not used by any other list, macro, or rule.",
"An unknown top-level object is in the rules content. It will be ignored."
};
const std::string& falco::load_result::warning_desc(warning_code wc)
{
return warning_descs[wc];
}

View File

@@ -0,0 +1,94 @@
/*
Copyright (C) 2022 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 <nlohmann/json.hpp>
namespace falco
{
// Represents the result of loading a rules file.
class load_result {
public:
enum error_code {
LOAD_ERR_FILE_READ = 0,
LOAD_ERR_YAML_PARSE,
LOAD_ERR_YAML_VALIDATE,
LOAD_ERR_COMPILE_CONDITION,
LOAD_ERR_COMPILE_OUTPUT,
LOAD_ERR_VALIDATE
};
// The error code as a string
static const std::string& error_code_str(error_code ec);
// A short string representation of the error
static const std::string& error_str(error_code ec);
// A longer description of what the error represents and the
// impact.
static const std::string& error_desc(error_code ec);
enum warning_code {
LOAD_UNKNOWN_SOURCE = 0,
LOAD_UNSAFE_NA_CHECK,
LOAD_NO_EVTTYPE,
LOAD_UNKNOWN_FIELD,
LOAD_UNUSED_MACRO,
LOAD_UNUSED_LIST,
LOAD_UNKNOWN_ITEM
};
// The warning code as a string
static const std::string& warning_code_str(warning_code ec);
// A short string representation of the warning
static const std::string& warning_str(warning_code ec);
// A longer description of what the warning represents and the
// impact.
static const std::string& warning_desc(warning_code ec);
// If true, the rules were loaded successfully and can be used
// against events. If false, there were one or more
// errors--use one of the as_xxx methods to return information
// about why the rules could not be loaded.
virtual bool successful() = 0;
// If true, there were one or more warnings. successful() and
// has_warnings() can both be true if there were only warnings.
virtual bool has_warnings() = 0;
// This contains a human-readable version of the result,
// suitable for display to end users.
//
// When verbose is true, the returned value has full details
// on the result including document locations/context.
//
// When verbose is false, the returned value is a short string
// with the success value and a list of
// errors/warnings. Suitable for simple one-line display.
virtual const std::string& as_string(bool verbose) = 0;
// This contains the full result structure as json, suitable
// for automated parsing/interpretation downstream.
virtual const nlohmann::json& as_json() = 0;
};
} // namespace falco

View File

@@ -48,9 +48,8 @@ void filter_evttype_resolver::visitor::evttypes(string evtname, set<uint16_t>& o
const struct ppm_event_info* etable = g_infotables.m_event_info;
for(uint16_t i = 2; i < PPM_EVENT_MAX; i++)
{
// Skip "old" event versions, unused events, or events not matching
// the requested evtname
if(!(etable[i].flags & (EF_OLD_VERSION | EF_UNUSED))
// Skip unused events or events not matching the requested evtname
if(!(etable[i].flags & EF_UNUSED)
&& (evtname.empty() || string(etable[i].name) == evtname))
{
out.insert(i);

View File

@@ -17,8 +17,9 @@ limitations under the License.
#include <sinsp.h>
#include "filter_warning_resolver.h"
using namespace falco;
static const char* no_value = "<NA>";
static const char* warn_unsafe_na_check = "unsafe-na-check";
static inline bool is_unsafe_field(const string& f)
{
@@ -34,7 +35,7 @@ static inline bool is_equality_operator(const string& op)
bool filter_warning_resolver::run(
libsinsp::filter::ast::expr* filter,
std::set<string>& warnings) const
std::set<load_result::warning_code>& warnings) const
{
visitor v;
auto size = warnings.size();
@@ -44,22 +45,6 @@ bool filter_warning_resolver::run(
return warnings.size() > size;
}
// todo(jasondellaluce): use an hard-coded map once we support more warnings
bool filter_warning_resolver::format(
const std::string& code,
std::string& out) const
{
if (code == warn_unsafe_na_check)
{
out = "comparing a field value with <NA> is unsafe and can lead to "
"unpredictable behavior of the rule condition. If you need to "
" check for the existence of a field, consider using the "
"'exists' operator instead.";
return true;
}
return false;
}
void filter_warning_resolver::visitor::visit(
libsinsp::filter::ast::binary_check_expr* e)
{
@@ -76,7 +61,7 @@ void filter_warning_resolver::visitor::visit(
{
if (m_is_equality_check && e->value == no_value)
{
m_warnings->insert(warn_unsafe_na_check);
m_warnings->insert(load_result::LOAD_UNSAFE_NA_CHECK);
}
}
@@ -86,6 +71,6 @@ void filter_warning_resolver::visitor::visit(
if (m_is_equality_check
&& std::find(e->values.begin(), e->values.end(), no_value) != e->values.end())
{
m_warnings->insert(warn_unsafe_na_check);
m_warnings->insert(load_result::LOAD_UNSAFE_NA_CHECK);
}
}
}

View File

@@ -21,6 +21,7 @@ limitations under the License.
#include <set>
#include <memory>
#include "falco_common.h"
#include "falco_load_result.h"
/*!
\brief Searches for bad practices in filter conditions and
@@ -42,40 +43,13 @@ public:
*/
bool run(
libsinsp::filter::ast::expr* filter,
std::set<std::string>& warnings) const;
/*!
\brief Given a warning code retrieved through run(), returns
a verbose message describing the problem of the warning.
\param code The warning code string
\param out The string to be filled-out with the warning message
\return true if the warning code is recognized, false otherwise
*/
bool format(const std::string& code, std::string& out) const;
/*!
\brief Given a warning code retrieved through run(), returns
a verbose message describing the problem of the warning.
\param code The warning code string
\return The warning message string
\throw falco_exception if the warning code is not recognized
*/
inline std::string format(const std::string& code) const
{
std::string v;
if (!format(code, v))
{
throw falco_exception("unrecognized warning code: " + code);
}
return v;
}
std::set<falco::load_result::warning_code>& warnings) const;
private:
struct visitor : public libsinsp::filter::ast::base_expr_visitor
{
bool m_is_equality_check;
std::set<std::string>* m_warnings;
std::set<falco::load_result::warning_code>* m_warnings;
void visit(libsinsp::filter::ast::value_expr* e) override;
void visit(libsinsp::filter::ast::list_expr* e) override;

File diff suppressed because it is too large Load Diff

View File

@@ -20,8 +20,10 @@ limitations under the License.
#include <string>
#include <vector>
#include <yaml-cpp/yaml.h>
#include <nlohmann/json.hpp>
#include "falco_rule.h"
#include "falco_source.h"
#include "falco_load_result.h"
#include "indexed_vector.h"
@@ -31,34 +33,111 @@ limitations under the License.
class rule_loader
{
public:
/*!
\brief Represents a section of text from which a certain info
struct has been decoded
*/
struct context
class context
{
std::string content;
/*!
\brief Wraps an error by adding info about the text section
*/
inline std::string error(std::string err) const
public:
struct location
{
std::string cnt = content;
err += "\n---\n";
err += trim(cnt);
err += "\n---";
return err;
}
// The original location in the document
YAML::Mark mark;
/*!
\brief Appends another text section info to this one
*/
inline void append(context& m)
{
content += "\n\n";
content += m.content;
}
// The kind of item at this location
// (e.g. "list", "macro", "rule", "exception", etc)
std::string item_type;
// The name of this item (e.g. "Write Below Etc",
// etc).
std::string item_name;
};
context(const std::string& name);
context(const YAML::Node& mark,
const std::string item_type,
const std::string item_name,
const context& parent);
virtual ~context() = default;
// Return a snippet of the provided rules content
// corresponding to this context.
std::string snippet(const std::string& content) const;
std::string as_string();
nlohmann::json as_json();
private:
std::string name;
// A chain of locations from the current item, its
// parent, possibly older ancestors.
std::vector<location> m_locs;
};
struct warning
{
falco::load_result::warning_code wc;
std::string msg;
context ctx;
std::string snippet;
};
struct error
{
falco::load_result::error_code ec;
std::string msg;
context ctx;
std::string snippet;
};
class rule_load_exception : public std::exception
{
public:
rule_load_exception(falco::load_result::error_code ec, std::string msg, const context& ctx);
virtual ~rule_load_exception();
const char* what();
falco::load_result::error_code ec;
std::string msg;
context ctx;
std::string errstr;
};
/*!
\brief Contains the result of loading rule definitions
*/
class result : public falco::load_result
{
public:
result(const std::string &name);
virtual ~result() = default;
virtual bool successful() override;
virtual bool has_warnings() override;
virtual const std::string& as_string(bool verbose) override;
virtual const nlohmann::json& as_json() override;
void add_error(falco::load_result::error_code ec,
const std::string& msg,
const context& ctx,
const std::string& rules_content);
void add_warning(falco::load_result::warning_code ec,
const std::string& msg,
const context& ctx,
const std::string& rules_content);
protected:
const std::string& as_summary_string();
const std::string& as_verbose_string();
std::string name;
bool success;
std::vector<error> errors;
std::vector<warning> warnings;
std::string res_summary_string;
std::string res_verbose_string;
nlohmann::json res_json;
};
/*!
@@ -68,13 +147,17 @@ public:
{
explicit configuration(
const std::string& cont,
const indexed_vector<falco_source>& srcs)
: content(cont), sources(srcs) {}
const indexed_vector<falco_source>& srcs,
std::string name)
: content(cont), sources(srcs), name(name)
{
res.reset(new result(name));
}
const std::string& content;
const indexed_vector<falco_source>& sources;
std::vector<std::string> errors;
std::vector<std::string> warnings;
std::string name;
std::unique_ptr<result> res;
std::string output_extra;
uint16_t default_ruleset_id;
bool replace_output_container_info;
@@ -86,6 +169,10 @@ public:
*/
struct engine_version_info
{
engine_version_info(context &ctx);
~engine_version_info() = default;
context ctx;
uint32_t version;
};
@@ -94,15 +181,26 @@ public:
*/
struct plugin_version_info
{
// This differs from the other _info structs by having
// a default constructor. This allows it to be used
// by falco_engine, which aliases the type.
plugin_version_info();
plugin_version_info(context &ctx);
~plugin_version_info() = default;
context ctx;
std::string name;
std::string version;
};
/*!
\brief Represents infos about a list
\brief Represents infos about a list
*/
struct list_info
{
list_info(context &ctx);
~list_info() = default;
context ctx;
bool used;
size_t index;
@@ -112,11 +210,15 @@ public:
};
/*!
\brief Represents infos about a macro
\brief Represents infos about a macro
*/
struct macro_info
{
macro_info(context &ctx);
~macro_info() = default;
context ctx;
context cond_ctx;
bool used;
size_t index;
size_t visibility;
@@ -130,6 +232,9 @@ public:
*/
struct rule_exception_info
{
rule_exception_info(context &ctx);
~rule_exception_info() = default;
/*!
\brief This is necessary due to the dynamic-typed nature of
exceptions. Each of fields, comps, and values, can either be a
@@ -148,6 +253,7 @@ public:
}
};
context ctx;
std::string name;
entry fields;
entry comps;
@@ -155,11 +261,16 @@ public:
};
/*!
\brief Represents infos about a rule
\brief Represents infos about a rule
*/
struct rule_info
{
rule_info(context &ctx);
~rule_info() = default;
context ctx;
context cond_ctx;
context output_ctx;
size_t index;
size_t visibility;
std::string name;
@@ -185,7 +296,7 @@ public:
/*!
\brief Uses the internal state to compile a list of falco_rules
*/
virtual bool compile(configuration& cfg, indexed_vector<falco_rule>& out) const;
virtual void compile(configuration& cfg, indexed_vector<falco_rule>& out) const;
/*!
\brief Returns the set of all required versions for each plugin according

View File

@@ -16,139 +16,222 @@ limitations under the License.
#include "rule_reader.h"
#define THROW(cond, err) { if (cond) { throw falco_exception(err); } }
#define THROW(cond, err, ctx) { if ((cond)) { throw rule_loader::rule_load_exception(load_result::LOAD_ERR_YAML_VALIDATE, (err), (ctx)); } }
static rule_loader::context yaml_get_context(
const string& content,
const vector<YAML::Node>& docs,
vector<YAML::Node>::iterator doc,
YAML::iterator node)
{
rule_loader::context m;
YAML::Node item = *node++;
YAML::Node cur_doc = *doc++;
// include the "- " sequence mark
size_t from = item.Mark().pos - 2;
size_t to = 0;
if (node != cur_doc.end())
{
// end of item is beginning of next item
to = node->Mark().pos - 2;
}
else if (doc != docs.end())
{
// end of item is beginning of next doc
to = doc->Mark().pos - 4;
}
else
{
// end of item is end of file contents
to = content.length();
}
m.content = content.substr(from, to - from);
m.content = trim(m.content);
return m;
}
using namespace falco;
// Don't call this directly, call decode_val/decode_optional_val instead.
template <typename T>
static bool decode_val(const YAML::Node& v, T& out)
static void decode_val_generic(const YAML::Node& item, const char *key, T& out, const rule_loader::context& ctx, bool optional)
{
return v.IsDefined() && v.IsScalar() && YAML::convert<T>::decode(v, out);
}
const YAML::Node& val = item[key];
template <typename T>
static bool decode_seq(const YAML::Node& item, vector<T>& out)
{
if (item.IsDefined() && item.IsSequence())
{
T value;
for(const YAML::Node& v : item)
{
THROW(!v.IsScalar() || !YAML::convert<T>::decode(v, value),
"Can't decode YAML sequence value: " + YAML::Dump(v));
out.push_back(value);
}
return true;
}
return false;
}
template <typename T>
static bool decode_seq(const YAML::Node& item, set<T>& out)
{
if (item.IsDefined() && item.IsSequence())
{
T value;
for(const YAML::Node& v : item)
{
THROW(!v.IsScalar() || !YAML::convert<T>::decode(v, value),
"Can't decode YAML sequence value: " + YAML::Dump(v));
out.insert(value);
}
return true;
}
return false;
}
static bool decode_exception_info_entry(
const YAML::Node& item,
rule_loader::rule_exception_info::entry& out)
{
if (item.IsDefined())
{
if (item.IsScalar())
{
out.is_list = false;
if (YAML::convert<string>::decode(item, out.item))
{
return true;
}
}
if (item.IsSequence())
{
out.is_list = true;
rule_loader::rule_exception_info::entry tmp;
for(const YAML::Node& v : item)
{
if (!decode_exception_info_entry(v, tmp))
{
return false;
}
out.items.push_back(tmp);
}
return true;
}
}
return false;
}
static void read_rule_exceptions(
const YAML::Node& item,
rule_loader::rule_info& v)
{
// An exceptions property with nothing in it is allowed
if(item.IsNull())
if(!val.IsDefined() && optional)
{
return;
}
THROW(!item.IsSequence(), "Rule exceptions must be a sequence");
for (auto &ex : item)
THROW(!val.IsDefined(), std::string("Item has no mapping for key '") + key + "'", ctx);
THROW(val.IsNull(), std::string("Mapping for key '") + key + "' is empty", ctx);
rule_loader::context valctx(val, "value for", key, ctx);
THROW(!val.IsScalar(), "Value is not a scalar value", valctx);
THROW(val.Scalar().empty(), "Value must be non-empty", valctx);
THROW(!YAML::convert<T>::decode(val, out), "Can't decode YAML scalar value", valctx);
}
template <typename T>
static void decode_val(const YAML::Node& item, const char *key, T& out, const rule_loader::context& ctx)
{
bool optional = false;
decode_val_generic(item, key, out, ctx, optional);
}
template <typename T>
static void decode_optional_val(const YAML::Node& item, const char *key, T& out, const rule_loader::context& ctx)
{
bool optional = true;
decode_val_generic(item, key, out, ctx, optional);
}
// Don't call this directly, call decode_items/decode_tags instead.
template <typename T>
static void decode_seq(const YAML::Node& item, const char *key,
std::function<void(T)> inserter,
const rule_loader::context &ctx, bool optional)
{
const YAML::Node& val = item[key];
if(!val.IsDefined() && optional)
{
rule_loader::rule_exception_info v_ex;
THROW(!decode_val(ex["name"], v_ex.name) || v_ex.name.empty(),
"Rule exception item must have name property");
// note: the legacy lua loader used to throw a "xxx must strings" error
decode_exception_info_entry(ex["fields"], v_ex.fields);
decode_exception_info_entry(ex["comps"], v_ex.comps);
if (ex["values"].IsDefined())
return;
}
THROW(!val.IsDefined(), std::string("Item has no mapping for key '") + key + "'", ctx);
rule_loader::context valctx(val, "value for", key, ctx);
THROW(!val.IsSequence(), "Value is not a sequence", valctx);
T value;
for(const YAML::Node& v : val)
{
rule_loader::context ictx(v, "list item", "", valctx);
THROW(!v.IsScalar(), "sequence value is not scalar", ictx);
THROW(!YAML::convert<T>::decode(v, value), "Can't decode YAML sequence value", ictx);
inserter(value);
}
}
template <typename T>
static void decode_items(const YAML::Node& item, vector<T>& out,
const rule_loader::context& ctx)
{
bool optional = false;
std::function<void(T)> inserter = [&out] (T value) {
out.push_back(value);
};
decode_seq(item, "items", inserter, ctx, optional);
}
template <typename T>
static void decode_tags(const YAML::Node& item, set<T>& out,
const rule_loader::context& ctx)
{
bool optional = true;
std::function<void(T)> inserter = [&out] (T value) {
out.insert(value);
};
decode_seq(item, "tags", inserter, ctx, optional);
}
// Don't call this directly, call decode_exception_{fields,comps,values} instead
static void decode_exception_info_entry(
const YAML::Node& item,
const char *key,
rule_loader::rule_exception_info::entry& out,
const rule_loader::context& ctx,
bool optional)
{
const YAML::Node& val = (key == NULL ? item : item[key]);
if(!val.IsDefined() && optional)
{
return;
}
THROW(!val.IsDefined(), std::string("Item has no mapping for key '") + key + "'", ctx);
rule_loader::context valctx(val, "value for", (key == NULL ? "" : key), ctx);
if (val.IsScalar())
{
THROW(val.Scalar().empty(), "Value must be non-empty", valctx);
out.is_list = false;
THROW(!YAML::convert<string>::decode(val, out.item), "Could not decode scalar value", valctx);
}
if (val.IsSequence())
{
out.is_list = true;
rule_loader::rule_exception_info::entry tmp;
for(const YAML::Node& v : val)
{
THROW(!ex["values"].IsSequence(),
"Rule exception values must be a sequence");
for (auto &val : ex["values"])
rule_loader::context lctx(v, "list exception entry", "", valctx);
// Optional is always false once you get past the outer values
optional = false;
decode_exception_info_entry(v, NULL, tmp, lctx, optional);
out.items.push_back(tmp);
}
}
}
static void decode_exception_fields(
const YAML::Node& item,
rule_loader::rule_exception_info::entry& out,
const rule_loader::context& ctx,
bool optional)
{
decode_exception_info_entry(item, "fields", out, ctx, optional);
}
static void decode_exception_comps(
const YAML::Node& item,
rule_loader::rule_exception_info::entry& out,
const rule_loader::context& ctx)
{
bool optional = true;
decode_exception_info_entry(item, "comps", out, ctx, optional);
}
static void decode_exception_values(
const YAML::Node& item,
rule_loader::rule_exception_info::entry& out,
const rule_loader::context& ctx)
{
bool optional = false;
decode_exception_info_entry(item, NULL, out, ctx, optional);
}
static void read_rule_exceptions(
const YAML::Node& item,
rule_loader::rule_info& v,
const rule_loader::context& parent,
bool append)
{
const YAML::Node& exs = item["exceptions"];
// No exceptions property, or an exceptions property with
// nothing in it, are allowed
if(!exs.IsDefined() || exs.IsNull())
{
return;
}
rule_loader::context exes_ctx(exs, "exceptions", "", parent);
THROW(!exs.IsSequence(), "Rule exceptions must be a sequence", exes_ctx);
for (auto &ex : exs)
{
// Make a temp context to verify simple properties
// about the exception.
std::string name;
rule_loader::context tmp(ex, "exception", "", exes_ctx);
THROW(!ex.IsMap(), "Rule exception must be a mapping", tmp);
decode_val(ex, "name", name, tmp);
// Now use a real context including the exception name.
rule_loader::context ex_ctx(ex, "exception", name, parent);
rule_loader::rule_exception_info v_ex(ex_ctx);
v_ex.name = name;
// note: the legacy lua loader used to throw a "xxx must strings" error
// fields are optional when append is true
decode_exception_fields(ex, v_ex.fields, ex_ctx, append);
decode_exception_comps(ex, v_ex.comps, ex_ctx);
const YAML::Node& exvals = ex["values"];
if (exvals.IsDefined())
{
rule_loader::context vals_ctx(exvals, "exception values", "", ex_ctx);
THROW(!exvals.IsSequence(),
"Rule exception values must be a sequence", vals_ctx);
for (auto &val : exvals)
{
rule_loader::context vctx(val, "exception value", "", vals_ctx);
rule_loader::rule_exception_info::entry v_ex_val;
decode_exception_info_entry(val, v_ex_val);
decode_exception_values(val, v_ex_val, vctx);
v_ex.values.push_back(v_ex_val);
}
}
@@ -157,43 +240,65 @@ static void read_rule_exceptions(
}
static void read_item(
rule_loader::configuration& cfg,
rule_loader& loader,
const YAML::Node& item,
const rule_loader::context& ctx)
rule_loader::configuration& cfg,
rule_loader& loader,
const YAML::Node& item,
const rule_loader::context& parent)
{
rule_loader::context tmp(item, "item", "", parent);
THROW(!item.IsMap(), "Unexpected element type. "
"Each element should be a yaml associative array.", tmp);
if (item["required_engine_version"].IsDefined())
{
rule_loader::engine_version_info v;
THROW(!decode_val(item["required_engine_version"], v.version),
"Value of required_engine_version must be a number");
rule_loader::context ctx(item, "required_engine_version", "", parent);
rule_loader::engine_version_info v(ctx);
decode_val(item, "required_engine_version", v.version, ctx);
loader.define(cfg, v);
}
else if(item["required_plugin_versions"].IsDefined())
{
THROW(!item["required_plugin_versions"].IsSequence(),
"Value of required_plugin_versions must be a sequence");
const YAML::Node& req_plugin_vers = item["required_plugin_versions"];
rule_loader::context ctx(req_plugin_vers, "required_plugin_versions", "", parent);
for(const YAML::Node& plugin : item["required_plugin_versions"])
THROW(!req_plugin_vers.IsSequence(),
"Value of required_plugin_versions must be a sequence",
ctx);
for(const YAML::Node& plugin : req_plugin_vers)
{
rule_loader::plugin_version_info v;
THROW(!decode_val(plugin["name"], v.name) || v.name.empty(),
"required_plugin_versions item must have name property");
THROW(!decode_val(plugin["version"], v.version) || v.version.empty(),
"required_plugin_versions item must have version property");
// Use a temp context until we can get a name
std::string name;
rule_loader::context tmp(plugin, "plugin version", "", ctx);
THROW(!plugin.IsMap(), "Plugin version must be a mapping", tmp);
decode_val(plugin, "name", name, tmp);
rule_loader::context pctx(plugin, "plugin version", name, ctx);
rule_loader::plugin_version_info v(pctx);
decode_val(plugin, "version", v.version, pctx);
v.name = name;
loader.define(cfg, v);
}
}
else if(item["list"].IsDefined())
{
rule_loader::list_info v;
v.ctx = ctx;
std::string name;
// Using tmp context until name is decoded
rule_loader::context tmp(item, "list", "", parent);
decode_val(item, "list", name, tmp);
rule_loader::context ctx(item, "list", name, parent);
rule_loader::list_info v(ctx);
bool append = false;
THROW(!decode_val(item["list"], v.name) || v.name.empty(),
"List name is empty");
THROW(!decode_seq(item["items"], v.items),
"List must have property items");
if(decode_val(item["append"], append) && append)
decode_val(item, "list", v.name, ctx);
decode_items(item, v.items, ctx);
decode_optional_val(item, "append", append, ctx);
if(append)
{
loader.append(cfg, v);
}
@@ -204,14 +309,24 @@ static void read_item(
}
else if(item["macro"].IsDefined())
{
rule_loader::macro_info v;
v.ctx = ctx;
std::string name;
// Using tmp context until name is decoded
rule_loader::context tmp(item, "macro", "", parent);
decode_val(item, "macro", name, tmp);
rule_loader::context ctx(item, "macro", name, parent);
rule_loader::macro_info v(ctx);
v.name = name;
bool append = false;
THROW(!decode_val(item["macro"], v.name) || v.name.empty(),
"Macro name is empty");
THROW(!decode_val(item["condition"], v.cond) || v.cond.empty(),
"Macro must have property condition");
if(decode_val(item["append"], append) && append)
decode_val(item, "condition", v.cond, ctx);
// Now set the proper context for the condition now that we know it exists
v.cond_ctx = rule_loader::context(item["condition"], "condition", "", ctx);
decode_optional_val(item, "append", append, ctx);
if(append)
{
loader.append(cfg, v);
}
@@ -222,57 +337,81 @@ static void read_item(
}
else if(item["rule"].IsDefined())
{
rule_loader::rule_info v;
v.ctx = ctx;
std::string name;
// Using tmp context until name is decoded
rule_loader::context tmp(item, "rule", "", parent);
decode_val(item, "rule", name, tmp);
rule_loader::context ctx(item, "rule", name, parent);
rule_loader::rule_info v(ctx);
v.name = name;
bool append = false;
v.enabled = true;
v.warn_evttypes = true;
v.skip_if_unknown_filter = false;
THROW(!decode_val(item["rule"], v.name) || v.name.empty(),
"Rule name is empty");
if(decode_val(item["append"], append) && append)
decode_optional_val(item, "append", append, ctx);
if(append)
{
decode_val(item["condition"], v.cond);
if (item["exceptions"].IsDefined())
decode_optional_val(item, "condition", v.cond, ctx);
if(item["condition"].IsDefined())
{
read_rule_exceptions(item["exceptions"], v);
v.cond_ctx = rule_loader::context(item["condition"], "condition", "", ctx);
}
read_rule_exceptions(item, v, ctx, append);
loader.append(cfg, v);
}
else
{
string priority;
bool has_enabled = decode_val(item["enabled"], v.enabled);
bool has_defs = decode_val(item["condition"], v.cond)
&& decode_val(item["output"], v.output)
&& decode_val(item["desc"], v.desc)
&& decode_val(item["priority"], priority);
if (!has_defs)
// If the rule does *not* have any of
// condition/output/desc/priority, it *must*
// have an enabled property. Use the enabled
// property to set the enabled status of an
// earlier rule.
if (!item["condition"].IsDefined() &&
!item["output"].IsDefined() &&
!item["desc"].IsDefined() &&
!item["priority"].IsDefined())
{
THROW(!has_enabled, "Rule must have properties 'condition', 'output', 'desc', and 'priority'");
decode_val(item, "enabled", v.enabled, ctx);
loader.enable(cfg, v);
}
else
{
string priority;
// All of these are required
decode_val(item, "condition", v.cond, ctx);
v.cond_ctx = rule_loader::context(item["condition"], "condition", "", ctx);
decode_val(item, "output", v.output, ctx);
v.output_ctx = rule_loader::context(item["output"], "output", "", ctx);
decode_val(item, "desc", v.desc, ctx);
decode_val(item, "priority", priority, ctx);
v.output = trim(v.output);
v.source = falco_common::syscall_source;
rule_loader::context prictx(item["priority"], "priority value", "", ctx);
THROW(!falco_common::parse_priority(priority, v.priority),
"Invalid priority");
decode_val(item["source"], v.source);
decode_val(item["warn_evttypes"], v.warn_evttypes);
decode_val(item["skip-if-unknown-filter"], v.skip_if_unknown_filter);
decode_seq(item["tags"], v.tags);
if (item["exceptions"].IsDefined())
{
read_rule_exceptions(item["exceptions"], v);
}
"Invalid priority", prictx);
decode_optional_val(item, "source", v.source, ctx);
decode_optional_val(item, "enabled", v.enabled, ctx);
decode_optional_val(item, "warn_evttypes", v.warn_evttypes, ctx);
decode_optional_val(item, "skip-if-unknown-filter", v.skip_if_unknown_filter, ctx);
decode_tags(item, v.tags, ctx);
read_rule_exceptions(item, v, ctx, append);
loader.define(cfg, v);
}
}
}
else
{
cfg.warnings.push_back("Unknown top level object");
rule_loader::context ctx(item, "unknown", "", parent);
cfg.res->add_warning(load_result::LOAD_UNKNOWN_ITEM, "Unknown top level item", ctx, cfg.content);
}
}
@@ -285,45 +424,45 @@ bool rule_reader::load(rule_loader::configuration& cfg, rule_loader& loader)
}
catch(const exception& e)
{
cfg.errors.push_back("Could not load YAML file: " + string(e.what()));
rule_loader::context ctx(cfg.name);
cfg.res->add_error(load_result::LOAD_ERR_YAML_PARSE, e.what(), ctx, cfg.content);
return false;
}
for (auto doc = docs.begin(); doc != docs.end(); doc++)
{
if (doc->IsDefined() && !doc->IsNull())
{
if(!doc->IsMap() && !doc->IsSequence())
{
cfg.errors.push_back("Rules content is not yaml");
return false;
}
if(!doc->IsSequence())
{
cfg.errors.push_back(
"Rules content is not yaml array of objects");
return false;
}
for (auto it = doc->begin(); it != doc->end(); it++)
{
if (!it->IsNull())
rule_loader::context ctx(cfg.name);
try {
THROW(!doc->IsMap() && !doc->IsSequence(),
"Rules content is not yaml",
ctx);
THROW(!doc->IsSequence(),
"Rules content is not yaml array of objects",
ctx);
for (auto it = doc->begin(); it != doc->end(); it++)
{
auto ctx = yaml_get_context(cfg.content, docs, doc, it);
YAML::Node item = *it;
try
if (!it->IsNull())
{
THROW(!item.IsMap(), "Unexpected element type. "
"Each element should be a yaml associative array.");
read_item(cfg, loader, item, ctx);
}
catch(const exception& e)
{
cfg.errors.push_back(ctx.error(e.what()));
return false;
read_item(cfg, loader, *it, ctx);
}
}
}
catch (rule_loader::rule_load_exception &e)
{
cfg.res->add_error(e.ec, e.msg, e.ctx, cfg.content);
// Although we *could* continue on to the next doc,
// as it's effectively a new rules file, for
// consistency we stop at the first error.
return false;
};
}
}
return true;
}

View File

@@ -21,7 +21,7 @@ using namespace falco::app;
application::run_result application::init_clients()
{
#ifndef MINIMAL_BUILD
// k8s and mesos clients are useful only if syscall source is enabled
// k8s client is useful only if the syscall source is enabled
if (!is_syscall_source_enabled())
{
return run_result::ok();
@@ -55,23 +55,6 @@ application::run_result application::init_clients()
}
m_state->inspector->init_k8s_client(k8s_api_ptr, k8s_api_cert_ptr, k8s_node_name_ptr, m_options.verbose);
}
//
// Run mesos, if required
//
if(!m_options.mesos_api.empty())
{
// Differs from init_k8s_client in that it
// passes a pointer but the inspector does
// *not* own it and does not use it after
// init_mesos_client() returns.
m_state->inspector->init_mesos_client(&(m_options.mesos_api), m_options.verbose);
}
else if(char* mesos_api_env = getenv("FALCO_MESOS_API"))
{
std::string mesos_api_copy = mesos_api_env;
m_state->inspector->init_mesos_client(&mesos_api_copy, m_options.verbose);
}
#endif
return run_result::ok();

View File

@@ -14,6 +14,8 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
#include <sstream>
#include "application.h"
using namespace falco::app;
@@ -33,11 +35,6 @@ void application::configure_output_format()
output_format = "k8s.ns=%k8s.ns.name k8s.pod=%k8s.pod.name container=%container.id";
replace_container_info = true;
}
else if(m_options.print_additional == "m" || m_options.print_additional == "mesos")
{
output_format = "task=%mesos.task.name container=%container.id";
replace_container_info = true;
}
else if(!m_options.print_additional.empty())
{
output_format = m_options.print_additional;
@@ -89,6 +86,13 @@ application::run_result application::init_falco_engine()
return run_result::fatal("At least one event source needs to be enabled");
}
/* Print all enabled sources. */
std::ostringstream os;
std::copy(m_state->enabled_sources.begin(), m_state->enabled_sources.end(), std::ostream_iterator<std::string>(os, ","));
std::string result = os.str();
result.pop_back();
falco_logger::log(LOG_INFO, "Enabled sources: " + result + "\n");
m_state->engine->set_min_priority(m_state->config->m_min_priority);
return run_result::ok();

View File

@@ -26,8 +26,9 @@ application::run_result application::load_config()
falco_logger::set_time_format_iso_8601(m_state->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) + "\n");
falco_logger::log(LOG_INFO, "Falco initialized with configuration file " + m_options.conf_filename + "\n");
falco_logger::log(LOG_INFO, "Falco version: " + std::string(FALCO_VERSION) + "\n");
falco_logger::log(LOG_INFO, "Falco initialized with configuration file: " + m_options.conf_filename + "\n");
falco_logger::log(LOG_INFO, "Falco compiled for: " + std::string(FALCO_TARGET_ARCH) + "\n");
}
else
{

View File

@@ -95,17 +95,26 @@ application::run_result application::load_rules_files()
for (const auto& filename : m_state->config->m_loaded_rules_filenames)
{
falco_logger::log(LOG_INFO, "Loading rules from file " + filename + ":\n");
uint64_t required_engine_version;
falco_logger::log(LOG_INFO, "Loading rules from file " + filename + "\n");
std::unique_ptr<falco::load_result> res;
try {
m_state->engine->load_rules_file(filename, m_options.verbose, m_options.all_events, required_engine_version);
}
catch(falco_exception &e)
res = m_state->engine->load_rules_file(filename);
// Print the full output if verbose is true
if(m_options.verbose &&
(!res->successful() || res->has_warnings()))
{
return run_result::fatal(string("Could not load rules file ") + filename + ": " + e.what());
printf("%s\n",
(m_state->config->m_json_output ?
res->as_json().dump().c_str() :
res->as_string(true).c_str()));
}
if(!res->successful())
{
// Return the summary version as the error
return run_result::fatal(res->as_string(false));
}
m_state->required_engine_versions[filename] = required_engine_version;
}
// Ensure that all plugins are compatible with the loaded set of rules

View File

@@ -83,6 +83,14 @@ application::run_result application::open_inspector()
}
}
/// TODO: we can add a method to the inspector that tells us what
/// is the underline engine used. Right now we print something only
/// in case of BPF engine
if(m_state->inspector->is_bpf_enabled())
{
falco_logger::log(LOG_INFO, "Falco is using the BPF probe\n");
}
// This must be done after the open
if(!m_options.all_events)
{

View File

@@ -58,7 +58,6 @@ application::run_result application::print_support()
nlohmann::json finfo;
finfo["name"] = filename;
nlohmann::json variant;
variant["required_engine_version"] = m_state->required_engine_versions[filename];
variant["content"] = read_file(filename);
finfo["variants"].push_back(variant);
support["rules_files"].push_back(finfo);

View File

@@ -123,6 +123,10 @@ application::run_result application::do_inspect(syscall_evt_drop_mgr &sdropmgr,
continue;
}
else if(rc == SCAP_FILTERED_EVENT)
{
continue;
}
else if(rc == SCAP_EOF)
{
break;

View File

@@ -15,6 +15,7 @@ limitations under the License.
*/
#include "application.h"
#include <string>
using namespace falco::app;
@@ -22,27 +23,64 @@ application::run_result application::validate_rules_files()
{
if(m_options.validate_rules_filenames.size() > 0)
{
bool successful = true;
std::string summary;
falco_logger::log(LOG_INFO, "Validating rules file(s):\n");
for(auto file : m_options.validate_rules_filenames)
{
falco_logger::log(LOG_INFO, " " + file + "\n");
}
// The json output encompasses all files so the
// validation result is a single json object.
nlohmann::json results = nlohmann::json::array();
for(auto file : m_options.validate_rules_filenames)
{
// Only include the prefix if there is more than one file
std::string prefix = (m_options.validate_rules_filenames.size() > 1 ? file + ": " : "");
try {
m_state->engine->load_rules_file(file, m_options.verbose, m_options.all_events);
}
catch(falco_exception &e)
std::unique_ptr<falco::load_result> res;
res = m_state->engine->load_rules_file(file);
successful &= res->successful();
if(summary != "")
{
printf("%s%s", prefix.c_str(), e.what());
return run_result::fatal(prefix + e.what());
summary += "\n";
}
summary += file + ": " + (res->successful() ? "Ok" : "Invalid");
if(m_state->config->m_json_output)
{
results.push_back(res->as_json());
}
else
{
// Print the full output when verbose is true
if(m_options.verbose &&
(!res->successful() || res->has_warnings()))
{
printf("%s\n", res->as_string(true).c_str());
}
}
printf("%sOk\n", prefix.c_str());
}
falco_logger::log(LOG_INFO, "Ok\n");
return run_result::exit();
if(m_state->config->m_json_output)
{
nlohmann::json res;
res["falco_load_results"] = results;
printf("%s\n", res.dump().c_str());
}
if(successful)
{
printf("%s\n", summary.c_str());
return run_result::exit();
}
else
{
return run_result::fatal(summary);
}
}
return run_result::ok();

View File

@@ -180,16 +180,13 @@ void cmdline_options::define()
("list-syscall-events", "List all defined system call events.", cxxopts::value<bool>(list_syscall_events))
#ifndef MUSL_OPTIMIZED
("list-plugins", "Print info on all loaded plugins and exit.", cxxopts::value(list_plugins)->default_value("false"))
#endif
#ifndef MINIMAL_BUILD
("m,mesos-api", "Enable Mesos support by connecting to the API server specified as argument. E.g. \"http://admin:password@127.0.0.1:5050\". Marathon url is optional and defaults to Mesos address, port 8080. The API servers can also be specified via the environment variable FALCO_MESOS_API.", cxxopts::value(mesos_api), "<url[,marathon_url]>")
#endif
("M", "Stop collecting after <num_seconds> reached.", cxxopts::value(duration_to_tot)->default_value("0"), "<num_seconds>")
("markdown", "When used with --list/--list-syscall-events, print the content in Markdown format", cxxopts::value<bool>(markdown))
("N", "When used with --list, only print field names.", cxxopts::value(names_only)->default_value("false"))
("o,option", "Set the value of option <opt> to <val>. Overrides values in configuration file. <opt> can be identified using its location in configuration file using dot notation. Elements which are entries of lists can be accessed via square brackets [].\n E.g. base.id = val\n base.subvalue.subvalue2 = val\n base.list[1]=val", cxxopts::value(cmdline_config_options), "<opt>=<val>")
("plugin-info", "Print info for a single plugin and exit.\nThis includes all descriptivo info like name and author, along with the\nschema format for the init configuration and a list of suggested open parameters.\n<plugin_name> can be the name of the plugin or its configured library_path.", cxxopts::value(print_plugin_info), "<plugin_name>")
("p,print", "Add additional information to each falco notification's output.\nWith -pc or -pcontainer will use a container-friendly format.\nWith -pk or -pkubernetes will use a kubernetes-friendly format.\nWith -pm or -pmesos will use a mesos-friendly format.\nAdditionally, specifying -pc/-pk/-pm will change the interpretation of %container.info in rule output fields.", cxxopts::value(print_additional), "<output_format>")
("p,print", "Add additional information to each falco notification's output.\nWith -pc or -pcontainer will use a container-friendly format.\nWith -pk or -pkubernetes will use a kubernetes-friendly format.\nAdditionally, specifying -pc/-pk will change the interpretation of %container.info in rule output fields.", cxxopts::value(print_additional), "<output_format>")
("P,pidfile", "When run as a daemon, write pid to specified file", cxxopts::value(pidfilename)->default_value("/var/run/falco.pid"), "<pid_file>")
("r", "Rules file/directory (defaults to value set in configuration file, or /etc/falco_rules.yaml). Can be specified multiple times to read from multiple files/directories.", cxxopts::value<std::vector<std::string>>(), "<rules_file>")
("s", "If specified, append statistics related to Falco's reading/processing of events to this file (only useful in live mode).", cxxopts::value(stats_filename), "<stats_file>")

View File

@@ -58,7 +58,6 @@ public:
std::string print_plugin_info;
bool list_syscall_events;
bool markdown;
std::string mesos_api;
int duration_to_tot;
bool names_only;
std::vector<std::string> cmdline_config_options;

View File

@@ -81,8 +81,6 @@ private:
// from event source to filtercheck list.
std::map<std::string, filter_check_list> plugin_filter_checks;
std::map<string,uint64_t> required_engine_versions;
std::string cmdline;
#ifndef MINIMAL_BUILD

View File

@@ -24,6 +24,7 @@ limitations under the License.
#define FALCO_VERSION_PATCH @FALCO_VERSION_PATCH@
#define FALCO_VERSION_PRERELEASE "@FALCO_VERSION_PRERELEASE@"
#define FALCO_VERSION_BUILD "@FALCO_VERSION_BUILD@"
#define FALCO_TARGET_ARCH "@FALCO_TARGET_ARCH@"
#define FALCO_SOURCE_DIR "${PROJECT_SOURCE_DIR}"
#define FALCO_SOURCE_CONF_FILE "${PROJECT_SOURCE_DIR}/falco.yaml"
@@ -33,4 +34,4 @@ limitations under the License.
#define FALCOSECURITY_LIBS_VERSION "${FALCOSECURITY_LIBS_VERSION}"
#define DRIVER_NAME "@DRIVER_NAME@"
#define DRIVER_VERSION "@DRIVER_VERSION@"
#define DRIVER_VERSION "@DRIVER_VERSION@"

View File

@@ -73,6 +73,18 @@ bool syscall_evt_drop_mgr::process_event(std::shared_ptr<sinsp> inspector, sinsp
delta.n_evts = stats.n_evts - m_last_stats.n_evts;
delta.n_drops = stats.n_drops - m_last_stats.n_drops;
delta.n_drops_buffer = stats.n_drops_buffer - m_last_stats.n_drops_buffer;
delta.n_drops_buffer_clone_fork_enter = stats.n_drops_buffer_clone_fork_enter - m_last_stats.n_drops_buffer_clone_fork_enter;
delta.n_drops_buffer_clone_fork_exit = stats.n_drops_buffer_clone_fork_exit - m_last_stats.n_drops_buffer_clone_fork_exit;
delta.n_drops_buffer_execve_enter = stats.n_drops_buffer_execve_enter - m_last_stats.n_drops_buffer_execve_enter;
delta.n_drops_buffer_execve_exit = stats.n_drops_buffer_execve_exit - m_last_stats.n_drops_buffer_execve_exit;
delta.n_drops_buffer_connect_enter = stats.n_drops_buffer_connect_enter - m_last_stats.n_drops_buffer_connect_enter;
delta.n_drops_buffer_connect_exit = stats.n_drops_buffer_connect_exit - m_last_stats.n_drops_buffer_connect_exit;
delta.n_drops_buffer_open_enter = stats.n_drops_buffer_open_enter - m_last_stats.n_drops_buffer_open_enter;
delta.n_drops_buffer_open_exit = stats.n_drops_buffer_open_exit - m_last_stats.n_drops_buffer_open_exit;
delta.n_drops_buffer_dir_file_enter = stats.n_drops_buffer_dir_file_enter - m_last_stats.n_drops_buffer_dir_file_enter;
delta.n_drops_buffer_dir_file_exit = stats.n_drops_buffer_dir_file_exit - m_last_stats.n_drops_buffer_dir_file_exit;
delta.n_drops_buffer_other_interest_enter = stats.n_drops_buffer_other_interest_enter - m_last_stats.n_drops_buffer_other_interest_enter;
delta.n_drops_buffer_other_interest_exit = stats.n_drops_buffer_other_interest_exit - m_last_stats.n_drops_buffer_other_interest_exit;
delta.n_drops_scratch_map = stats.n_drops_scratch_map - m_last_stats.n_drops_scratch_map;
delta.n_drops_pf = stats.n_drops_pf - m_last_stats.n_drops_pf;
delta.n_drops_bug = stats.n_drops_bug - m_last_stats.n_drops_bug;
@@ -91,8 +103,8 @@ bool syscall_evt_drop_mgr::process_event(std::shared_ptr<sinsp> inspector, sinsp
if(delta.n_drops > 0)
{
double ratio = delta.n_drops;
// Assuming the number of event does not contains the dropped ones
ratio /= delta.n_drops + delta.n_evts;
// The `n_evts` always contains the `n_drops`.
ratio /= delta.n_evts;
// When simulating drops the threshold is always zero
if(ratio > m_threshold)
@@ -146,12 +158,35 @@ bool syscall_evt_drop_mgr::perform_actions(uint64_t now, scap_stats &delta, bool
case syscall_evt_drop_action::ALERT:
{
std::map<std::string, std::string> output_fields;
output_fields["n_evts"] = std::to_string(delta.n_evts);
output_fields["n_drops"] = std::to_string(delta.n_drops);
output_fields["n_drops_buffer"] = std::to_string(delta.n_drops_buffer);
output_fields["n_drops_scratch_map"] = std::to_string(delta.n_drops_scratch_map);
output_fields["n_drops_pf"] = std::to_string(delta.n_drops_pf);
output_fields["n_drops_bug"] = std::to_string(delta.n_drops_bug);
output_fields["n_evts"] = std::to_string(delta.n_evts); /* Total number of kernel side events actively traced (not including events discarded due to simple consumer mode in eBPF case). */
output_fields["n_drops"] = std::to_string(delta.n_drops); /* Number of all kernel side event drops out of n_evts. */
output_fields["n_drops_buffer_total"] = std::to_string(delta.n_drops_buffer); /* Total number of kernel side drops due to full buffer, includes all categories below, likely higher than sum of syscall categories. */
/* Kernel side drops due to full buffer for categories of system calls. Not all system calls of interest are mapped into one of the categories.
* Insights:
* (1) Identify statistical properties of workloads (e.g. ratios between categories).
* (2) Data-driven optimization opportunity for kernel side filtering and prioritization.
* (3) Response: Coarse grained insights into syscalls dropped.
* (4) Bonus: Cost associated with syscall category (typically `open` system call category is highest by orders of magnitude).
*/
output_fields["n_drops_buffer_clone_fork_enter"] = std::to_string(delta.n_drops_buffer_clone_fork_enter);
output_fields["n_drops_buffer_clone_fork_exit"] = std::to_string(delta.n_drops_buffer_clone_fork_exit);
output_fields["n_drops_buffer_execve_enter"] = std::to_string(delta.n_drops_buffer_execve_enter);
output_fields["n_drops_buffer_execve_exit"] = std::to_string(delta.n_drops_buffer_execve_exit);
output_fields["n_drops_buffer_connect_enter"] = std::to_string(delta.n_drops_buffer_connect_enter);
output_fields["n_drops_buffer_connect_exit"] = std::to_string(delta.n_drops_buffer_connect_exit);
output_fields["n_drops_buffer_open_enter"] = std::to_string(delta.n_drops_buffer_open_enter);
output_fields["n_drops_buffer_open_exit"] = std::to_string(delta.n_drops_buffer_open_exit);
output_fields["n_drops_buffer_dir_file_enter"] = std::to_string(delta.n_drops_buffer_dir_file_enter);
output_fields["n_drops_buffer_dir_file_exit"] = std::to_string(delta.n_drops_buffer_dir_file_exit);
/* `n_drops_buffer_other_interest_*` Category consisting of other system calls of interest,
* not all other system calls that did not match a category from above.
* Ideal for a custom category if needed - simply patch switch statement in kernel driver code (`falcosecurity/libs` repo).
*/
output_fields["n_drops_buffer_other_interest_enter"] = std::to_string(delta.n_drops_buffer_other_interest_enter);
output_fields["n_drops_buffer_other_interest_exit"] = std::to_string(delta.n_drops_buffer_other_interest_exit);
output_fields["n_drops_scratch_map"] = std::to_string(delta.n_drops_scratch_map); /* Number of kernel side scratch map drops. */
output_fields["n_drops_page_faults"] = std::to_string(delta.n_drops_pf); /* Number of kernel side page faults drops (invalid memory access). */
output_fields["n_drops_bug"] = std::to_string(delta.n_drops_bug); /* Number of kernel side bug drops (invalid condition in the kernel instrumentation). */
output_fields["ebpf_enabled"] = std::to_string(bpf_enabled);
m_outputs->handle_msg(now, falco_common::PRIORITY_DEBUG, msg, rule, output_fields);
break;

View File

@@ -16,9 +16,11 @@ limitations under the License.
#include <sys/time.h>
#include <signal.h>
#include <nlohmann/json.hpp>
#include "statsfilewriter.h"
#include "banned.h" // This raises a compilation error when certain functions are used
#include "logger.h"
using namespace std;
@@ -28,8 +30,6 @@ static void timer_handler (int signum)
g_save_stats = true;
}
extern char **environ;
StatsFileWriter::StatsFileWriter()
: m_num_stats(0)
{
@@ -67,30 +67,6 @@ bool StatsFileWriter::init(std::shared_ptr<sinsp> inspector, string &filename, u
return false;
}
// (Undocumented) feature. Take any environment keys prefixed
// with FALCO_STATS_EXTRA_XXX and add them to the output. Used by
// run_performance_tests.sh.
for(uint32_t i=0; environ[i]; i++)
{
char *p = strstr(environ[i], "=");
if(!p)
{
errstr = string("Could not find environment separator in ") + string(environ[i]);
return false;
}
string key(environ[i], p-environ[i]);
string val(p+1, strlen(environ[i])-(p-environ[i])-1);
if(key.compare(0, 18, "FALCO_STATS_EXTRA_") == 0)
{
string sub = key.substr(18);
if (m_extra != "")
{
m_extra += ", ";
}
m_extra += "\"" + sub + "\": " + "\"" + val + "\"";
}
}
return true;
}
@@ -100,6 +76,7 @@ void StatsFileWriter::handle()
{
scap_stats cstats;
scap_stats delta;
nlohmann::json jmsg;
g_save_stats = false;
m_num_stats++;
@@ -116,21 +93,23 @@ void StatsFileWriter::handle()
delta.n_preemptions = cstats.n_preemptions - m_last_stats.n_preemptions;
}
m_output << "{\"sample\": " << m_num_stats;
if(m_extra != "")
try
{
m_output << ", " << m_extra;
jmsg["sample"] = m_num_stats;
jmsg["cur"]["events"] = cstats.n_evts;
jmsg["cur"]["drops"] = cstats.n_drops;
jmsg["cur"]["preemptions"] = cstats.n_preemptions;
jmsg["cur"]["drop_pct"] = (cstats.n_evts == 0 ? 0 : (100.0*cstats.n_drops/cstats.n_evts));
jmsg["delta"]["events"] = delta.n_evts;
jmsg["delta"]["drops"] = delta.n_drops;
jmsg["delta"]["preemptions"] = delta.n_preemptions;
jmsg["delta"]["drop_pct"] = (delta.n_evts == 0 ? 0 : (100.0*delta.n_drops/delta.n_evts));
m_output << jmsg.dump() << endl;
}
catch(const exception &e)
{
falco_logger::log(LOG_ERR, "StatsFileWriter (handle): " + string(e.what()) + "\n");
}
m_output << ", \"cur\": {" <<
"\"events\": " << cstats.n_evts <<
", \"drops\": " << cstats.n_drops <<
", \"preemptions\": " << cstats.n_preemptions <<
"}, \"delta\": {" <<
"\"events\": " << delta.n_evts <<
", \"drops\": " << delta.n_drops <<
", \"preemptions\": " << delta.n_preemptions <<
"}, \"drop_pct\": " << (delta.n_evts == 0 ? 0 : (100.0*delta.n_drops/delta.n_evts)) <<
"}," << endl;
m_last_stats = cstats;
}

View File

@@ -43,6 +43,5 @@ protected:
uint32_t m_num_stats;
std::shared_ptr<sinsp> m_inspector;
std::ofstream m_output;
std::string m_extra;
scap_stats m_last_stats;
};