mirror of
https://github.com/falcosecurity/falco.git
synced 2026-03-21 12:12:28 +00:00
Compare commits
176 Commits
0.15.2
...
feat/modul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1d676f949 | ||
|
|
73f70cd0ef | ||
|
|
b1edc405c2 | ||
|
|
efe39b4360 | ||
|
|
a04ac1def3 | ||
|
|
f710edcde2 | ||
|
|
7a3d5c62a0 | ||
|
|
435a3b01db | ||
|
|
acd3e7f23a | ||
|
|
deaae756c0 | ||
|
|
5a6c7af0c5 | ||
|
|
05565f3524 | ||
|
|
980fb2f3a9 | ||
|
|
ba5e59964d | ||
|
|
60721d52cb | ||
|
|
8d9f88d45a | ||
|
|
4c04821d48 | ||
|
|
fc2c1ac6cb | ||
|
|
295c7afc32 | ||
|
|
f10b170174 | ||
|
|
9f9d0e751b | ||
|
|
322a2cdd25 | ||
|
|
5c5c2e3309 | ||
|
|
71832bc3ad | ||
|
|
93a3d14c41 | ||
|
|
c7e7a868ed | ||
|
|
193f33cd40 | ||
|
|
14853597d3 | ||
|
|
49c4ef5d8c | ||
|
|
1eeb059e10 | ||
|
|
870c17e31d | ||
|
|
c713b89542 | ||
|
|
7d8e1dee9b | ||
|
|
39b51562ed | ||
|
|
f05d18a847 | ||
|
|
731e197108 | ||
|
|
e229cecbe1 | ||
|
|
3ea98b05dd | ||
|
|
7bc3fa165f | ||
|
|
3a1ab88111 | ||
|
|
2439e97da6 | ||
|
|
8c62ec5472 | ||
|
|
c9cd6eebf7 | ||
|
|
723bc1cabf | ||
|
|
330d7ef2d7 | ||
|
|
1fc509d78b | ||
|
|
a7ee01103d | ||
|
|
03fbf432f1 | ||
|
|
94d89eaea2 | ||
|
|
76f64f5d79 | ||
|
|
3dbd43749a | ||
|
|
2439873a96 | ||
|
|
204f5f219d | ||
|
|
9b7c7ff5e4 | ||
|
|
1f0065e4b1 | ||
|
|
bcf83057fa | ||
|
|
46b1a3c841 | ||
|
|
a42ec9d7c7 | ||
|
|
3fedd00cfc | ||
|
|
4a4701b4fd | ||
|
|
40111a5d6e | ||
|
|
323a9ef51d | ||
|
|
49752fc81a | ||
|
|
4224329905 | ||
|
|
b7c35d3b54 | ||
|
|
d1c642cbd2 | ||
|
|
b369de3801 | ||
|
|
95a7cf3ea8 | ||
|
|
dc03dbee18 | ||
|
|
8156c9214c | ||
|
|
d11ad9a005 | ||
|
|
c71703b566 | ||
|
|
8400066ac8 | ||
|
|
f18fc46a1c | ||
|
|
e598606505 | ||
|
|
7b2b0b14a5 | ||
|
|
e422337ed7 | ||
|
|
c4cd9e326a | ||
|
|
533e8247fd | ||
|
|
736aa92b5e | ||
|
|
3e1ab78536 | ||
|
|
38cf3c6f29 | ||
|
|
50f04897e5 | ||
|
|
62be14dde6 | ||
|
|
c5e296576d | ||
|
|
a5b063f5fa | ||
|
|
c61c0e7020 | ||
|
|
ebcb133f00 | ||
|
|
88503a1ea9 | ||
|
|
e1c2cac9c9 | ||
|
|
44f0633f47 | ||
|
|
9d4ed8e33e | ||
|
|
0d4fc4bdad | ||
|
|
85a94d67d3 | ||
|
|
f3c3cda879 | ||
|
|
e02318db7c | ||
|
|
9f7e3bdfcd | ||
|
|
2cda10caeb | ||
|
|
7efec602e8 | ||
|
|
8fb4c7f2f6 | ||
|
|
6e313742e7 | ||
|
|
e92a721521 | ||
|
|
d5aae4aff5 | ||
|
|
2aff2d00a3 | ||
|
|
d7956a2a09 | ||
|
|
9308c1ee55 | ||
|
|
40e3e21391 | ||
|
|
d6c089c917 | ||
|
|
9ab718c100 | ||
|
|
4b2ea32eac | ||
|
|
5acdb16e89 | ||
|
|
a084f8c4ed | ||
|
|
01f65e3bae | ||
|
|
1711ed0a2e | ||
|
|
839d76a760 | ||
|
|
dc7bff127f | ||
|
|
e80ff6296a | ||
|
|
231f881c5a | ||
|
|
cb5a3a14e6 | ||
|
|
4c68da0dcc | ||
|
|
a32870ae1d | ||
|
|
fdbd520cce | ||
|
|
f20a5a04bf | ||
|
|
affb1086a3 | ||
|
|
8155d467ab | ||
|
|
bf19d8c881 | ||
|
|
7501c3cb5d | ||
|
|
52a44c171c | ||
|
|
0e4f2ec17c | ||
|
|
047f12d0f6 | ||
|
|
c1035ce4de | ||
|
|
19c12042f4 | ||
|
|
e688ab7d0a | ||
|
|
b2ef08fd30 | ||
|
|
5fdf658d0e | ||
|
|
08454dfa53 | ||
|
|
9bc28951ad | ||
|
|
583be9ce22 | ||
|
|
71b2fe6e14 | ||
|
|
a09f71b457 | ||
|
|
1a0cf69b03 | ||
|
|
3a1c0ea916 | ||
|
|
fcc587e806 | ||
|
|
815f5d8714 | ||
|
|
11838548df | ||
|
|
8a745b73a3 | ||
|
|
fade424120 | ||
|
|
48f2b1d08a | ||
|
|
16bd8919ab | ||
|
|
6ce17d6fcb | ||
|
|
c12052e03d | ||
|
|
8ed33a04fd | ||
|
|
f4fea8441c | ||
|
|
93537ccaea | ||
|
|
4174822617 | ||
|
|
c2ac1d3622 | ||
|
|
adabae4f63 | ||
|
|
6e92988425 | ||
|
|
026f6866e3 | ||
|
|
18b66330ec | ||
|
|
acae9dd9f1 | ||
|
|
68340944b1 | ||
|
|
02d5c167ce | ||
|
|
29251f2078 | ||
|
|
e1655be243 | ||
|
|
03310800ed | ||
|
|
d158d99800 | ||
|
|
1d7c6c3356 | ||
|
|
147ec6073c | ||
|
|
3f200c52b0 | ||
|
|
88ed98ce81 | ||
|
|
18960b01b0 | ||
|
|
5beddf5320 | ||
|
|
2198147c35 | ||
|
|
cfaa52f522 | ||
|
|
4561c8b22e |
16
.clang-format
Normal file
16
.clang-format
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -8
|
||||
BreakBeforeBraces: Allman
|
||||
BreakConstructorInitializers: AfterColon
|
||||
ColumnLimit: 0
|
||||
ConstructorInitializerIndentWidth: 8
|
||||
ContinuationIndentWidth: 8
|
||||
DerivePointerAlignment: true
|
||||
IndentWidth: 8
|
||||
SortIncludes: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeCtorInitializerColon: false
|
||||
SpaceBeforeParens: Never
|
||||
UseTab: Always
|
||||
119
.cmake-format
Normal file
119
.cmake-format
Normal file
@@ -0,0 +1,119 @@
|
||||
# --------------------------
|
||||
# General Formatting Options
|
||||
# --------------------------
|
||||
# How wide to allow formatted cmake files
|
||||
line_width = 80
|
||||
|
||||
# How many spaces to tab for indent
|
||||
tab_size = 2
|
||||
|
||||
# If arglists are longer than this, break them always
|
||||
max_subargs_per_line = 3
|
||||
|
||||
# If true, separate flow control names from their parentheses with a space
|
||||
separate_ctrl_name_with_space = False
|
||||
|
||||
# If true, separate function names from parentheses with a space
|
||||
separate_fn_name_with_space = False
|
||||
|
||||
# If a statement is wrapped to more than one line, than dangle the closing
|
||||
# parenthesis on it's own line
|
||||
dangle_parens = False
|
||||
|
||||
# If the statement spelling length (including space and parenthesis is larger
|
||||
# than the tab width by more than this amoung, then force reject un-nested
|
||||
# layouts.
|
||||
max_prefix_chars = 2
|
||||
|
||||
# If a candidate layout is wrapped horizontally but it exceeds this many lines,
|
||||
# then reject the layout.
|
||||
max_lines_hwrap = 2
|
||||
|
||||
# What style line endings to use in the output.
|
||||
line_ending = 'unix'
|
||||
|
||||
# Format command names consistently as 'lower' or 'upper' case
|
||||
command_case = 'canonical'
|
||||
|
||||
# Format keywords consistently as 'lower' or 'upper' case
|
||||
keyword_case = 'unchanged'
|
||||
|
||||
# Specify structure for custom cmake functions
|
||||
additional_commands = {
|
||||
"pkg_find": {
|
||||
"kwargs": {
|
||||
"PKG": "*"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# A list of command names which should always be wrapped
|
||||
always_wrap = []
|
||||
|
||||
# Specify the order of wrapping algorithms during successive reflow attempts
|
||||
algorithm_order = [0, 1, 2, 3, 4]
|
||||
|
||||
# If true, the argument lists which are known to be sortable will be sorted
|
||||
# lexicographicall
|
||||
enable_sort = True
|
||||
|
||||
# If true, the parsers may infer whether or not an argument list is sortable
|
||||
# (without annotation).
|
||||
autosort = False
|
||||
|
||||
# If a comment line starts with at least this many consecutive hash characters,
|
||||
# then don't lstrip() them off. This allows for lazy hash rulers where the first
|
||||
# hash char is not separated by space
|
||||
hashruler_min_length = 10
|
||||
|
||||
# A dictionary containing any per-command configuration overrides. Currently
|
||||
# only `command_case` is supported.
|
||||
per_command = {}
|
||||
|
||||
|
||||
# --------------------------
|
||||
# Comment Formatting Options
|
||||
# --------------------------
|
||||
# What character to use for bulleted lists
|
||||
bullet_char = '*'
|
||||
|
||||
# What character to use as punctuation after numerals in an enumerated list
|
||||
enum_char = '.'
|
||||
|
||||
# enable comment markup parsing and reflow
|
||||
enable_markup = True
|
||||
|
||||
# If comment markup is enabled, don't reflow the first comment block in each
|
||||
# listfile. Use this to preserve formatting of your copyright/license
|
||||
# statements.
|
||||
first_comment_is_literal = False
|
||||
|
||||
# If comment markup is enabled, don't reflow any comment block which matches
|
||||
# this (regex) pattern. Default is `None` (disabled).
|
||||
literal_comment_pattern = None
|
||||
|
||||
# Regular expression to match preformat fences in comments
|
||||
# default=r'^\s*([`~]{3}[`~]*)(.*)$'
|
||||
fence_pattern = '^\\s*([`~]{3}[`~]*)(.*)$'
|
||||
|
||||
# Regular expression to match rulers in comments
|
||||
# default=r'^\s*[^\w\s]{3}.*[^\w\s]{3}$'
|
||||
ruler_pattern = '^\\s*[^\\w\\s]{3}.*[^\\w\\s]{3}$'
|
||||
|
||||
# If true, then insert a space between the first hash char and remaining hash
|
||||
# chars in a hash ruler, and normalize it's length to fill the column
|
||||
canonicalize_hashrulers = True
|
||||
|
||||
|
||||
# ---------------------------------
|
||||
# Miscellaneous Options
|
||||
# ---------------------------------
|
||||
# If true, emit the unicode byte-order mark (BOM) at the start of the file
|
||||
emit_byteorder_mark = False
|
||||
|
||||
# Specify the encoding of the input file. Defaults to utf-8.
|
||||
input_encoding = 'utf-8'
|
||||
|
||||
# Specify the encoding of the output file. Defaults to utf-8. Note that cmake
|
||||
# only claims to support utf-8 so be careful when using anything else
|
||||
output_encoding = 'utf-8'
|
||||
30
.github/PULL_REQUEST_TEMPLATE.md
vendored
30
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -7,48 +7,66 @@
|
||||
-->
|
||||
|
||||
**What type of PR is this?**
|
||||
> Uncomment only one ` /kind <>` line, hit enter to put that in a new line, and remove leading whitespaces from that line:
|
||||
>
|
||||
|
||||
> Uncomment one (or more) `/kind <>` lines:
|
||||
|
||||
> /kind bug
|
||||
|
||||
> /kind cleanup
|
||||
|
||||
> /kind design
|
||||
|
||||
> /kind documentation
|
||||
|
||||
> /kind failing-test
|
||||
|
||||
> /kind feature
|
||||
|
||||
> /kind flaky-test
|
||||
|
||||
> If contributing rules or changes to rules, please make sure to uncomment the appropriate kind
|
||||
> If contributing rules or changes to rules, please make sure to also uncomment one of the following line:
|
||||
|
||||
> /kind rule/update
|
||||
> /kind rule/create
|
||||
> /kind rule-update
|
||||
|
||||
> /kind rule-create
|
||||
|
||||
**Any specific area of the project related to this PR?**
|
||||
|
||||
> Uncomment one (or more) `/area <>` lines:
|
||||
|
||||
> /area engine
|
||||
|
||||
> /area rules
|
||||
|
||||
> /area deployment
|
||||
|
||||
> /area integrations
|
||||
|
||||
> /area examples
|
||||
|
||||
**What this PR does / why we need it**:
|
||||
|
||||
**Which issue(s) this PR fixes**:
|
||||
|
||||
<!--
|
||||
Automatically closes linked issue when PR is merged.
|
||||
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
|
||||
If PR is `kind/failing-tests` or `kind/flaky-test`, please post the related issues/tests in a comment and do not use `Fixes`.
|
||||
-->
|
||||
|
||||
Fixes #
|
||||
|
||||
**Special notes for your reviewer**:
|
||||
|
||||
**Does this PR introduce a user-facing change?**:
|
||||
|
||||
<!--
|
||||
If no, just write "NONE" in the release-note block below.
|
||||
If yes, a release note is required:
|
||||
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required:".
|
||||
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, prepend the string "action required:".
|
||||
For example, `action required: change the API interface of the rule engine`.
|
||||
-->
|
||||
|
||||
```release-note
|
||||
|
||||
```
|
||||
|
||||
10
.gitignore
vendored
10
.gitignore
vendored
@@ -3,19 +3,27 @@
|
||||
*.pyc
|
||||
|
||||
test/falco_tests.yaml
|
||||
test/falco_traces.yaml
|
||||
test/traces-negative
|
||||
test/traces-positive
|
||||
test/traces-info
|
||||
test/job-results
|
||||
test/build
|
||||
test/.phoronix-test-suite
|
||||
test/results*.json.*
|
||||
test/build
|
||||
|
||||
userspace/falco/lua/re.lua
|
||||
userspace/falco/lua/lpeg.so
|
||||
userspace/engine/lua/lyaml
|
||||
userspace/engine/lua/lyaml.lua
|
||||
|
||||
docker/event-generator/event_generator
|
||||
docker/event-generator/mysqld
|
||||
docker/event-generator/httpd
|
||||
docker/event-generator/sha1sum
|
||||
docker/event-generator/vipw
|
||||
.vscode/*
|
||||
|
||||
.vscode/*
|
||||
|
||||
.luacheckcache
|
||||
9
.luacheckrc
Normal file
9
.luacheckrc
Normal file
@@ -0,0 +1,9 @@
|
||||
std = "min"
|
||||
cache = true
|
||||
include_files = {
|
||||
"userspace/falco/lua/*.lua",
|
||||
"userspace/engine/lua/*.lua",
|
||||
"userspace/engine/lua/lyaml/*.lua",
|
||||
"*.luacheckrc"
|
||||
}
|
||||
exclude_files = {"build"}
|
||||
16
.travis.yml
16
.travis.yml
@@ -18,8 +18,8 @@
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
env:
|
||||
- BUILD_TYPE=Debug
|
||||
- BUILD_TYPE=Release
|
||||
- BUILD_TYPE=debug
|
||||
- BUILD_TYPE=release
|
||||
sudo: required
|
||||
services:
|
||||
- docker
|
||||
@@ -33,14 +33,4 @@ install:
|
||||
- pushd ../sysdig && (git checkout "${BRANCH}" || exit 0) && echo "Using sysdig branch:" $(git rev-parse --abbrev-ref HEAD) && popd
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- docker run --user $(id -u):$(id -g) -v /etc/passwd:/etc/passwd:ro -e MAKE_JOBS=4 -v $TRAVIS_BUILD_DIR/..:/source -v $TRAVIS_BUILD_DIR/build:/build falcosecurity/falco-builder cmake
|
||||
- docker run --user $(id -u):$(id -g) -v /etc/passwd:/etc/passwd:ro -e MAKE_JOBS=4 -v $TRAVIS_BUILD_DIR/..:/source -v $TRAVIS_BUILD_DIR/build:/build falcosecurity/falco-builder package
|
||||
- docker run -v /boot:/boot:ro -v /var/run/docker.sock:/var/run/docker.sock -v /etc/passwd:/etc/passwd:ro -e MAKE_JOBS=4 -v $TRAVIS_BUILD_DIR/..:/source -v $TRAVIS_BUILD_DIR/build:/build falcosecurity/falco-tester
|
||||
notifications:
|
||||
webhooks:
|
||||
urls:
|
||||
# - https://webhooks.gitter.im/e/fdbc2356fb0ea2f15033
|
||||
on_success: change
|
||||
on_failure: always
|
||||
on_start: never
|
||||
- ./scripts/build "${TRAVIS_BUILD_DIR}/.." "${TRAVIS_BUILD_DIR}/build"
|
||||
|
||||
8
.yamllint.conf
Normal file
8
.yamllint.conf
Normal file
@@ -0,0 +1,8 @@
|
||||
extends: default
|
||||
|
||||
rules:
|
||||
indentation: disable
|
||||
document-start: disable
|
||||
comments: disable
|
||||
line-length: disable
|
||||
new-line-at-end-of-file: disable
|
||||
118
CHANGELOG.md
118
CHANGELOG.md
@@ -2,6 +2,124 @@
|
||||
|
||||
This file documents all notable changes to Falco. The release numbering uses [semantic versioning](http://semver.org).
|
||||
|
||||
## v0.17.0
|
||||
|
||||
Released 2019-07-31
|
||||
|
||||
## Major Changes
|
||||
|
||||
* **The set of supported platforms has changed**. Switch to a reorganized builder image that uses Centos 7 as a base. As a result, falco is no longer supported on Centos 6. The other supported platforms should remain the same [[#719](https://github.com/falcosecurity/falco/pull/719)]
|
||||
|
||||
## Minor Changes
|
||||
|
||||
* When enabling rules within the falco engine, use rule substrings instead of regexes. [[#743](https://github.com/falcosecurity/falco/pull/743)]
|
||||
|
||||
* Additional improvements to the handling and display of rules validation errors [[#744](https://github.com/falcosecurity/falco/pull/744)] [[#747](https://github.com/falcosecurity/falco/pull/747)]
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
* Fix a problem that would cause prevent container metadata lookups when falco was daemonized [[#731](https://github.com/falcosecurity/falco/pull/731)]
|
||||
|
||||
* Allow rule priorites to be expressed as lowercase and a mix of lower/uppercase [[#737](https://github.com/falcosecurity/falco/pull/737)]
|
||||
|
||||
## Rule Changes
|
||||
|
||||
* Fix a parentheses bug with the `shell_procs` macro [[#728](https://github.com/falcosecurity/falco/pull/728)]
|
||||
|
||||
* Allow additional containers to mount sensitive host paths [[#733](https://github.com/falcosecurity/falco/pull/733)] [[#736](https://github.com/falcosecurity/falco/pull/736)]
|
||||
|
||||
* Allow additional containers to truncate log files [[#733](https://github.com/falcosecurity/falco/pull/733)]
|
||||
|
||||
* Fix false positives with the `Write below root` rule on GKE [[#739](https://github.com/falcosecurity/falco/pull/739)]
|
||||
|
||||
## v0.16.0
|
||||
|
||||
Released 2019-07-12
|
||||
|
||||
## Major Changes
|
||||
|
||||
* Clean up error reporting to provide more meaningful error messages along with context when loading rules files. When run with -V, the results of the validation ("OK" or error message) are sent to standard output. [[#708](https://github.com/falcosecurity/falco/pull/708)]
|
||||
|
||||
* Improve rule loading performance by optimizing lua parsing paths to avoid expensive pattern matches. [[#694](https://github.com/falcosecurity/falco/pull/694)]
|
||||
|
||||
* Bump falco engine version to 4 to reflect new fields `ka.useragent`, others. [[#710](https://github.com/falcosecurity/falco/pull/710)] [[#681](https://github.com/falcosecurity/falco/pull/681)]
|
||||
|
||||
* Add Catch2 as a unit testing framework. This will add additional coverage on top of the regression tests using Avocado. [[#687](https://github.com/falcosecurity/falco/pull/687)]
|
||||
|
||||
## Minor Changes
|
||||
|
||||
* Add SYSDIG_DIR Cmake option to specify location for sysdig source code when building falco. [[#677](https://github.com/falcosecurity/falco/pull/677)] [[#679](https://github.com/falcosecurity/falco/pull/679)] [[#702](https://github.com/falcosecurity/falco/pull/702)]
|
||||
|
||||
* New field `ka.useragent` reports the useragent from k8s audit events. [[#709](https://github.com/falcosecurity/falco/pull/709)]
|
||||
|
||||
* Add clang formatter for C++ syntax formatting. [[#701](https://github.com/falcosecurity/falco/pull/701)] [[#689](https://github.com/falcosecurity/falco/pull/689)]
|
||||
|
||||
* Partial changes towards lua syntax formatting. No particular formatting enforced yet, though. [[#718](https://github.com/falcosecurity/falco/pull/718)]
|
||||
|
||||
* Partial changes towards yaml syntax formatting. No particular formatting enforced yet, though. [[#714](https://github.com/falcosecurity/falco/pull/714)]
|
||||
|
||||
* Add cmake syntax formatting. [[#703](https://github.com/falcosecurity/falco/pull/703)]
|
||||
|
||||
* Token bucket unit tests and redesign. [[#692](https://github.com/falcosecurity/falco/pull/692)]
|
||||
|
||||
* Update github PR template. [[#699](https://github.com/falcosecurity/falco/pull/699)]
|
||||
|
||||
* Fix PR template for kind/rule-*. [[#697](https://github.com/falcosecurity/falco/pull/697)]
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
* Remove an unused cmake file. [[#700](https://github.com/falcosecurity/falco/pull/700)]
|
||||
|
||||
* Misc Cmake cleanups. [[#673](https://github.com/falcosecurity/falco/pull/673)]
|
||||
|
||||
* Misc k8s install docs improvements. [[#671](https://github.com/falcosecurity/falco/pull/671)]
|
||||
|
||||
## Rule Changes
|
||||
|
||||
* Allow k8s.gcr.io/kube-proxy image to run privileged. [[#717](https://github.com/falcosecurity/falco/pull/717)]
|
||||
|
||||
* Add runc to the list of possible container entrypoint parents. [[#712](https://github.com/falcosecurity/falco/pull/712)]
|
||||
|
||||
* Skip Source RFC 1918 addresses when considering outbound connections. [[#685](https://github.com/falcosecurity/falco/pull/685)]
|
||||
|
||||
* Add additional `user_XXX` placeholder macros to allow for easy customization of rule exceptions. [[#685](https://github.com/falcosecurity/falco/pull/685)]
|
||||
|
||||
* Let weaveworks programs change namespaces. [[#685](https://github.com/falcosecurity/falco/pull/685)]
|
||||
|
||||
* Add additional openshift images. [[#685](https://github.com/falcosecurity/falco/pull/685)]
|
||||
|
||||
* Add openshift as a k8s binary. [[#678](https://github.com/falcosecurity/falco/pull/678)]
|
||||
|
||||
* Add dzdo as a binary that can change users. [[#678](https://github.com/falcosecurity/falco/pull/678)]
|
||||
|
||||
* Allow azure/calico binaries to change namespaces. [[#678](https://github.com/falcosecurity/falco/pull/678)]
|
||||
|
||||
* Add back trusted_containers list for backport compatibility [[#675](https://github.com/falcosecurity/falco/pull/675)]
|
||||
|
||||
* Add mkdirat as a syscall for mkdir operations. [[#667](https://github.com/falcosecurity/falco/pull/667)]
|
||||
|
||||
* Add container id/repository to rules that can work with containers. [[#667](https://github.com/falcosecurity/falco/pull/667)]
|
||||
|
||||
## v0.15.3
|
||||
|
||||
Released 2019-06-12
|
||||
|
||||
## Major Changes
|
||||
|
||||
* None.
|
||||
|
||||
## Minor Changes
|
||||
|
||||
* None.
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
* Fix kernel module compilation for kernels < 3.11 [[#sysdig/1436](https://github.com/draios/sysdig/pull/1436)]
|
||||
|
||||
## Rule Changes
|
||||
|
||||
* None.
|
||||
|
||||
## v0.15.2
|
||||
|
||||
Released 2019-06-12
|
||||
|
||||
120
CMakeLists.txt
120
CMakeLists.txt
@@ -15,37 +15,45 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
cmake_minimum_required(VERSION 2.8.2)
|
||||
cmake_minimum_required(VERSION 3.3.2)
|
||||
|
||||
project(falco)
|
||||
|
||||
option(BUILD_WARNINGS_AS_ERRORS "Enable building with -Wextra -Werror flags")
|
||||
|
||||
if(NOT DEFINED FALCO_VERSION)
|
||||
set(FALCO_VERSION "0.1.1dev")
|
||||
if(NOT SYSDIG_DIR)
|
||||
get_filename_component(SYSDIG_DIR "${PROJECT_SOURCE_DIR}/../sysdig" REALPATH)
|
||||
endif()
|
||||
|
||||
# Custom CMake modules
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
|
||||
list(APPEND CMAKE_MODULE_PATH "${SYSDIG_DIR}/cmake/modules")
|
||||
|
||||
option(BUILD_WARNINGS_AS_ERRORS "Enable building with -Wextra -Werror flags")
|
||||
|
||||
if(NOT DEFINED FALCO_ETC_DIR)
|
||||
set(FALCO_ETC_DIR "/etc/falco")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
SET(CMAKE_BUILD_TYPE Release)
|
||||
endif()
|
||||
|
||||
if(NOT DRAIOS_DEBUG_FLAGS)
|
||||
set(DRAIOS_DEBUG_FLAGS "-D_DEBUG")
|
||||
endif()
|
||||
|
||||
string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE)
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "debug")
|
||||
set(KBUILD_FLAGS "${DRAIOS_DEBUG_FLAGS} ${DRAIOS_FEATURE_FLAGS}")
|
||||
else()
|
||||
set(CMAKE_BUILD_TYPE "release")
|
||||
set(KBUILD_FLAGS "${DRAIOS_FEATURE_FLAGS}")
|
||||
endif()
|
||||
|
||||
set(CMAKE_COMMON_FLAGS "-Wall -ggdb ${DRAIOS_FEATURE_FLAGS}")
|
||||
|
||||
if(BUILD_WARNINGS_AS_ERRORS)
|
||||
set(CMAKE_SUPPRESSED_WARNINGS "-Wno-unused-parameter -Wno-missing-field-initializers -Wno-sign-compare -Wno-type-limits -Wno-implicit-fallthrough -Wno-format-truncation")
|
||||
set(CMAKE_SUPPRESSED_WARNINGS "-Wno-unused-parameter -Wno-unused-variable -Wno-unused-but-set-variable -Wno-missing-field-initializers -Wno-sign-compare -Wno-type-limits -Wno-implicit-fallthrough -Wno-format-truncation")
|
||||
set(CMAKE_COMMON_FLAGS "${CMAKE_COMMON_FLAGS} -Wextra -Werror ${CMAKE_SUPPRESSED_WARNINGS}")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_COMMON_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "--std=c++0x ${CMAKE_COMMON_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "--std=c++11 ${CMAKE_COMMON_FLAGS}")
|
||||
|
||||
set(CMAKE_C_FLAGS_DEBUG "${DRAIOS_DEBUG_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${DRAIOS_DEBUG_FLAGS}")
|
||||
@@ -59,11 +67,28 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
add_definitions(-DHAS_CAPTURE)
|
||||
endif()
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(KBUILD_FLAGS "${DRAIOS_DEBUG_FLAGS} ${DRAIOS_FEATURE_FLAGS}")
|
||||
else()
|
||||
set(KBUILD_FLAGS "${DRAIOS_FEATURE_FLAGS}")
|
||||
# Create the falco version variable according to git index
|
||||
if(NOT FALCO_VERSION)
|
||||
include(GetGitRevisionDescription)
|
||||
git_get_exact_tag(FALCO_TAG)
|
||||
if(NOT FALCO_TAG)
|
||||
git_describe(FALCO_VERSION "--always")
|
||||
git_local_changes(FALCO_CHANGES)
|
||||
if(FALCO_CHANGES STREQUAL "DIRTY")
|
||||
string(TOLOWER "${FALCO_CHANGES}" FALCO_CHANGES)
|
||||
set(FALCO_VERSION "${FALCO_VERSION}.${FALCO_CHANGES}")
|
||||
endif()
|
||||
set(FALCO_VERSION "0.${FALCO_VERSION}")
|
||||
else()
|
||||
set(FALCO_VERSION "${FALCO_TAG}")
|
||||
string(REGEX
|
||||
REPLACE "^v([0-9]+)(\\.[0-9]+)(\\.[0-9]+)?"
|
||||
"\\1\\2\\3"
|
||||
FALCO_VERSION
|
||||
${FALCO_VERSION})
|
||||
endif()
|
||||
endif()
|
||||
message(STATUS "Falco version: ${FALCO_VERSION}")
|
||||
|
||||
set(PACKAGE_NAME "falco")
|
||||
set(PROBE_VERSION "${FALCO_VERSION}")
|
||||
@@ -75,7 +100,6 @@ endif()
|
||||
|
||||
set(CMD_MAKE make)
|
||||
|
||||
set(SYSDIG_DIR "${PROJECT_SOURCE_DIR}/../sysdig")
|
||||
# make luaJIT work on OS X
|
||||
if(APPLE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-pagezero_size 10000 -image_base 100000000")
|
||||
@@ -105,7 +129,7 @@ else()
|
||||
set(ZLIB_LIB "${ZLIB_SRC}/libz.a")
|
||||
ExternalProject_Add(zlib
|
||||
# START CHANGE for CVE-2016-9840, CVE-2016-9841, CVE-2016-9842, CVE-2016-9843
|
||||
URL "http://s3.amazonaws.com/download.draios.com/dependencies/zlib-1.2.11.tar.gz"
|
||||
URL "https://s3.amazonaws.com/download.draios.com/dependencies/zlib-1.2.11.tar.gz"
|
||||
URL_MD5 "1c9f62f0778697a09d36121ead88e08e"
|
||||
# END CHANGE for CVE-2016-9840, CVE-2016-9841, CVE-2016-9842, CVE-2016-9843
|
||||
CONFIGURE_COMMAND "./configure"
|
||||
@@ -132,12 +156,12 @@ else()
|
||||
set(JQ_INCLUDE "${JQ_SRC}")
|
||||
set(JQ_LIB "${JQ_SRC}/.libs/libjq.a")
|
||||
ExternalProject_Add(jq
|
||||
URL "http://s3.amazonaws.com/download.draios.com/dependencies/jq-1.5.tar.gz"
|
||||
URL "https://s3.amazonaws.com/download.draios.com/dependencies/jq-1.5.tar.gz"
|
||||
URL_MD5 "0933532b086bd8b6a41c1b162b1731f9"
|
||||
CONFIGURE_COMMAND ./configure --disable-maintainer-mode --enable-all-static --disable-dependency-tracking
|
||||
BUILD_COMMAND ${CMD_MAKE} LDFLAGS=-all-static
|
||||
BUILD_IN_SOURCE 1
|
||||
PATCH_COMMAND wget -O jq-1.5-fix-tokenadd.patch https://github.com/stedolan/jq/commit/8eb1367ca44e772963e704a700ef72ae2e12babd.patch && patch -i jq-1.5-fix-tokenadd.patch
|
||||
PATCH_COMMAND curl -L https://github.com/stedolan/jq/commit/8eb1367ca44e772963e704a700ef72ae2e12babd.patch | patch
|
||||
INSTALL_COMMAND "")
|
||||
endif()
|
||||
|
||||
@@ -164,7 +188,7 @@ else()
|
||||
message(STATUS "Using bundled nlohmann-json in '${NJSON_SRC}'")
|
||||
set(NJSON_INCLUDE "${NJSON_SRC}/single_include")
|
||||
ExternalProject_Add(njson
|
||||
URL "http://download.draios.com/dependencies/njson-3.3.0.tar.gz"
|
||||
URL "https://s3.amazonaws.com/download.draios.com/dependencies/njson-3.3.0.tar.gz"
|
||||
URL_MD5 "e26760e848656a5da400662e6c5d999a"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
@@ -188,7 +212,7 @@ else()
|
||||
set(CURSES_LIBRARIES "${CURSES_BUNDLE_DIR}/lib/libncurses.a")
|
||||
message(STATUS "Using bundled ncurses in '${CURSES_BUNDLE_DIR}'")
|
||||
ExternalProject_Add(ncurses
|
||||
URL "http://s3.amazonaws.com/download.draios.com/dependencies/ncurses-6.0-20150725.tgz"
|
||||
URL "https://s3.amazonaws.com/download.draios.com/dependencies/ncurses-6.0-20150725.tgz"
|
||||
URL_MD5 "32b8913312e738d707ae68da439ca1f4"
|
||||
CONFIGURE_COMMAND ./configure --without-cxx --without-cxx-binding --without-ada --without-manpages --without-progs --without-tests --with-terminfo-dirs=/etc/terminfo:/lib/terminfo:/usr/share/terminfo
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
@@ -215,7 +239,7 @@ else()
|
||||
set(B64_INCLUDE "${B64_SRC}/include")
|
||||
set(B64_LIB "${B64_SRC}/src/libb64.a")
|
||||
ExternalProject_Add(b64
|
||||
URL "http://s3.amazonaws.com/download.draios.com/dependencies/libb64-1.2.src.zip"
|
||||
URL "https://s3.amazonaws.com/download.draios.com/dependencies/libb64-1.2.src.zip"
|
||||
URL_MD5 "a609809408327117e2c643bed91b76c5"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
@@ -268,7 +292,7 @@ else()
|
||||
|
||||
ExternalProject_Add(openssl
|
||||
# START CHANGE for CVE-2017-3735, CVE-2017-3731, CVE-2017-3737, CVE-2017-3738, CVE-2017-3736
|
||||
URL "http://s3.amazonaws.com/download.draios.com/dependencies/openssl-1.0.2n.tar.gz"
|
||||
URL "https://s3.amazonaws.com/download.draios.com/dependencies/openssl-1.0.2n.tar.gz"
|
||||
URL_MD5 "13bdc1b1d1ff39b6fd42a255e74676a4"
|
||||
# END CHANGE for CVE-2017-3735, CVE-2017-3731, CVE-2017-3737, CVE-2017-3738, CVE-2017-3736
|
||||
CONFIGURE_COMMAND ./config shared --prefix=${OPENSSL_INSTALL_DIR}
|
||||
@@ -301,10 +325,10 @@ else()
|
||||
ExternalProject_Add(curl
|
||||
DEPENDS openssl
|
||||
# START CHANGE for CVE-2017-8816, CVE-2017-8817, CVE-2017-8818, CVE-2018-1000007
|
||||
URL "http://s3.amazonaws.com/download.draios.com/dependencies/curl-7.61.0.tar.bz2"
|
||||
URL "https://s3.amazonaws.com/download.draios.com/dependencies/curl-7.61.0.tar.bz2"
|
||||
URL_MD5 "31d0a9f48dc796a7db351898a1e5058a"
|
||||
# END CHANGE for CVE-2017-8816, CVE-2017-8817, CVE-2017-8818, CVE-2018-1000007
|
||||
CONFIGURE_COMMAND ./configure ${CURL_SSL_OPTION} --disable-shared --enable-optimize --disable-curldebug --disable-rt --enable-http --disable-ftp --disable-file --disable-ldap --disable-ldaps --disable-rtsp --disable-telnet --disable-tftp --disable-pop3 --disable-imap --disable-smb --disable-smtp --disable-gopher --disable-sspi --disable-ntlm-wb --disable-tls-srp --without-winssl --without-darwinssl --without-polarssl --without-cyassl --without-nss --without-axtls --without-ca-path --without-ca-bundle --without-libmetalink --without-librtmp --without-winidn --without-libidn --without-nghttp2 --without-libssh2 --disable-threaded-resolver
|
||||
CONFIGURE_COMMAND ./configure ${CURL_SSL_OPTION} --disable-shared --enable-optimize --disable-curldebug --disable-rt --enable-http --disable-ftp --disable-file --disable-ldap --disable-ldaps --disable-rtsp --disable-telnet --disable-tftp --disable-pop3 --disable-imap --disable-smb --disable-smtp --disable-gopher --disable-sspi --disable-ntlm-wb --disable-tls-srp --without-winssl --without-darwinssl --without-polarssl --without-cyassl --without-nss --without-axtls --without-ca-path --without-ca-bundle --without-libmetalink --without-librtmp --without-winidn --without-libidn2 --without-libpsl --without-nghttp2 --without-libssh2 --disable-threaded-resolver --without-brotli
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND "")
|
||||
@@ -336,7 +360,7 @@ else()
|
||||
set(LUAJIT_INCLUDE "${LUAJIT_SRC}")
|
||||
set(LUAJIT_LIB "${LUAJIT_SRC}/libluajit.a")
|
||||
ExternalProject_Add(luajit
|
||||
URL "http://s3.amazonaws.com/download.draios.com/dependencies/LuaJIT-2.0.3.tar.gz"
|
||||
URL "https://s3.amazonaws.com/download.draios.com/dependencies/LuaJIT-2.0.3.tar.gz"
|
||||
URL_MD5 "f14e9104be513913810cd59c8c658dc0"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
@@ -366,7 +390,7 @@ else()
|
||||
endif()
|
||||
ExternalProject_Add(lpeg
|
||||
DEPENDS ${LPEG_DEPENDENCIES}
|
||||
URL "http://s3.amazonaws.com/download.draios.com/dependencies/lpeg-1.0.0.tar.gz"
|
||||
URL "https://s3.amazonaws.com/download.draios.com/dependencies/lpeg-1.0.0.tar.gz"
|
||||
URL_MD5 "0aec64ccd13996202ad0c099e2877ece"
|
||||
BUILD_COMMAND LUA_INCLUDE=${LUAJIT_INCLUDE} "${PROJECT_SOURCE_DIR}/scripts/build-lpeg.sh" "${LPEG_SRC}/build"
|
||||
BUILD_IN_SOURCE 1
|
||||
@@ -378,7 +402,6 @@ endif()
|
||||
# Libyaml
|
||||
#
|
||||
option(USE_BUNDLED_LIBYAML "Enable building of the bundled libyaml" ${USE_BUNDLED_DEPS})
|
||||
|
||||
if(NOT USE_BUNDLED_LIBYAML)
|
||||
# Note: to distinguish libyaml.a and yaml.a we specify a full
|
||||
# file name here, so you'll have to arrange for static
|
||||
@@ -398,10 +421,11 @@ else()
|
||||
endif()
|
||||
|
||||
set(LIBYAML_SRC "${PROJECT_BINARY_DIR}/libyaml-prefix/src/libyaml/src")
|
||||
set(LIBYAML_INCLUDE "${PROJECT_BINARY_DIR}/libyaml-prefix/src/libyaml/include")
|
||||
set(LIBYAML_LIB "${LIBYAML_SRC}/.libs/libyaml.a")
|
||||
message(STATUS "Using bundled libyaml in '${LIBYAML_SRC}'")
|
||||
ExternalProject_Add(libyaml
|
||||
URL "http://s3.amazonaws.com/download.draios.com/dependencies/libyaml-0.1.4.tar.gz"
|
||||
URL "https://s3.amazonaws.com/download.draios.com/dependencies/libyaml-0.1.4.tar.gz"
|
||||
URL_MD5 "4a4bced818da0b9ae7fc8ebc690792a7"
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
@@ -413,7 +437,6 @@ endif()
|
||||
# lyaml
|
||||
#
|
||||
option(USE_BUNDLED_LYAML "Enable building of the bundled lyaml" ${USE_BUNDLED_DEPS})
|
||||
|
||||
if(NOT USE_BUNDLED_LYAML)
|
||||
# Note: to distinguish libyaml.a and yaml.a we specify a full
|
||||
# file name here, so you'll have to arrange for static
|
||||
@@ -435,14 +458,15 @@ else()
|
||||
if(USE_BUNDLED_LIBYAML)
|
||||
list(APPEND LYAML_DEPENDENCIES "libyaml")
|
||||
endif()
|
||||
|
||||
ExternalProject_Add(lyaml
|
||||
DEPENDS ${LYAML_DEPENDENCIES}
|
||||
URL "http://s3.amazonaws.com/download.draios.com/dependencies/lyaml-release-v6.0.tar.gz"
|
||||
URL_MD5 "dc3494689a0dce7cf44e7a99c72b1f30"
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND ./configure --enable-static LIBS=-L../../../libyaml-prefix/src/libyaml/src/.libs CFLAGS=-I../../../libyaml-prefix/src/libyaml/include CPPFLAGS=-I../../../libyaml-prefix/src/libyaml/include LUA_INCLUDE=-I../../../luajit-prefix/src/luajit/src LUA=../../../luajit-prefix/src/luajit/src/luajit
|
||||
INSTALL_COMMAND sh -c "cp -R ${PROJECT_BINARY_DIR}/lyaml-prefix/src/lyaml/lib/* ${PROJECT_SOURCE_DIR}/userspace/engine/lua")
|
||||
URL "https://s3.amazonaws.com/download.draios.com/dependencies/lyaml-release-v6.0.tar.gz"
|
||||
URL_MD5 "dc3494689a0dce7cf44e7a99c72b1f30"
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND ./configure --enable-static LIBS=-L${LIBYAML_SRC}/.libs CFLAGS=-I${LIBYAML_INCLUDE} CPPFLAGS=-I${LIBYAML_INCLUDE} LUA_INCLUDE=-I${LUAJIT_INCLUDE} LUA=${LUAJIT_SRC}/luajit
|
||||
INSTALL_COMMAND sh -c "cp -R ${PROJECT_BINARY_DIR}/lyaml-prefix/src/lyaml/lib/* ${PROJECT_SOURCE_DIR}/userspace/engine/lua")
|
||||
endif()
|
||||
|
||||
option(USE_BUNDLED_TBB "Enable building of the bundled tbb" ${USE_BUNDLED_DEPS})
|
||||
@@ -462,7 +486,7 @@ else()
|
||||
set(TBB_INCLUDE_DIR "${TBB_SRC}/include/")
|
||||
set(TBB_LIB "${TBB_SRC}/build/lib_release/libtbb.a")
|
||||
ExternalProject_Add(tbb
|
||||
URL "http://s3.amazonaws.com/download.draios.com/dependencies/tbb-2018_U5.tar.gz"
|
||||
URL "https://s3.amazonaws.com/download.draios.com/dependencies/tbb-2018_U5.tar.gz"
|
||||
URL_MD5 "ff3ae09f8c23892fbc3008c39f78288f"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ${CMD_MAKE} tbb_build_dir=${TBB_SRC}/build tbb_build_prefix=lib extra_inc=big_iron.inc
|
||||
@@ -494,7 +518,7 @@ else()
|
||||
endif()
|
||||
ExternalProject_Add(civetweb
|
||||
DEPENDS ${CIVETWEB_DEPENDENCIES}
|
||||
URL "http://s3.amazonaws.com/download.draios.com/dependencies/civetweb-1.11.tar.gz"
|
||||
URL "https://s3.amazonaws.com/download.draios.com/dependencies/civetweb-1.11.tar.gz"
|
||||
URL_MD5 "b6d2175650a27924bccb747cbe084cd4"
|
||||
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E make_directory ${CIVETWEB_SRC}/install/lib
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${CIVETWEB_SRC}/install/include
|
||||
@@ -582,16 +606,16 @@ else()
|
||||
|
||||
ExternalProject_Add(grpc
|
||||
DEPENDS protobuf zlib c-ares
|
||||
URL "http://download.draios.com/dependencies/grpc-1.8.1.tar.gz"
|
||||
URL "https://s3.amazonaws.com/download.draios.com/dependencies/grpc-1.8.1.tar.gz"
|
||||
URL_MD5 "2fc42c182a0ed1b48ad77397f76bb3bc"
|
||||
CONFIGURE_COMMAND ""
|
||||
# TODO what if using system openssl, protobuf or cares?
|
||||
BUILD_COMMAND HAS_SYSTEM_ZLIB=false LDFLAGS=-static PATH=${PROTOC_DIR}:$ENV{PATH} PKG_CONFIG_PATH=${OPENSSL_BUNDLE_DIR}:${PROTOBUF_SRC}:${CARES_SRC} make grpc_cpp_plugin static_cxx static_c
|
||||
BUILD_COMMAND sh -c "CFLAGS=-Wno-implicit-fallthrough CXXFLAGS=\"-Wno-ignored-qualifiers -Wno-stringop-truncation\" HAS_SYSTEM_ZLIB=false LDFLAGS=-static PATH=${PROTOC_DIR}:$ENV{PATH} PKG_CONFIG_PATH=${OPENSSL_BUNDLE_DIR}:${PROTOBUF_SRC}:${CARES_SRC} make grpc_cpp_plugin static_cxx static_c"
|
||||
BUILD_IN_SOURCE 1
|
||||
BUILD_BYPRODUCTS ${GRPC_LIB} ${GRPCPP_LIB}
|
||||
# TODO s390x support
|
||||
# TODO what if using system zlib
|
||||
PATCH_COMMAND rm -rf third_party/zlib && ln -s ${ZLIB_SRC} third_party/zlib && wget https://download.sysdig.com/dependencies/grpc-1.1.4-Makefile.patch && patch < grpc-1.1.4-Makefile.patch
|
||||
PATCH_COMMAND rm -rf third_party/zlib && ln -s ${ZLIB_SRC} third_party/zlib && curl -L https://download.sysdig.com/dependencies/grpc-1.1.4-Makefile.patch | patch
|
||||
INSTALL_COMMAND "")
|
||||
endif()
|
||||
|
||||
@@ -605,6 +629,7 @@ add_subdirectory(docker)
|
||||
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
add_subdirectory("${SYSDIG_DIR}/driver" "${PROJECT_BINARY_DIR}/driver")
|
||||
include(FindMakedev)
|
||||
endif()
|
||||
add_subdirectory("${SYSDIG_DIR}/userspace/libscap" "${PROJECT_BINARY_DIR}/userspace/libscap")
|
||||
add_subdirectory("${SYSDIG_DIR}/userspace/libsinsp" "${PROJECT_BINARY_DIR}/userspace/libsinsp")
|
||||
@@ -616,11 +641,12 @@ set(FALCO_BIN_DIR bin)
|
||||
add_subdirectory(scripts)
|
||||
add_subdirectory(userspace/engine)
|
||||
add_subdirectory(userspace/falco)
|
||||
|
||||
add_subdirectory(tests)
|
||||
|
||||
set(CPACK_PACKAGE_NAME "${PACKAGE_NAME}")
|
||||
set(CPACK_PACKAGE_VENDOR "Sysdig Inc.")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "falco, a system-level activity monitoring tool")
|
||||
set(CPACK_PACKAGE_CONTACT "opensource@sysdig.com")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Falco - Container Native Runtime Security")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/scripts/description.txt")
|
||||
set(CPACK_PACKAGE_VERSION "${FALCO_VERSION}")
|
||||
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_SYSTEM_PROCESSOR}")
|
||||
@@ -630,19 +656,19 @@ set(CPACK_PACKAGE_RELOCATABLE "OFF")
|
||||
|
||||
set(CPACK_GENERATOR DEB RPM TGZ)
|
||||
|
||||
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Sysdig <support@sysdig.com>")
|
||||
set(CPACK_DEBIAN_PACKAGE_SECTION "utils")
|
||||
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "http://www.sysdig.org")
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64")
|
||||
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://www.falco.org")
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "dkms (>= 2.1.0.0)")
|
||||
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_BINARY_DIR}/scripts/debian/postinst;${CMAKE_BINARY_DIR}/scripts/debian/prerm;${PROJECT_SOURCE_DIR}/scripts/debian/postrm;${PROJECT_SOURCE_DIR}/cpack/debian/conffiles")
|
||||
|
||||
set(CPACK_RPM_PACKAGE_LICENSE "Apache v2.0")
|
||||
set(CPACK_RPM_PACKAGE_URL "http://www.sysdig.org")
|
||||
set(CPACK_RPM_PACKAGE_URL "https://www.falco.org")
|
||||
set(CPACK_RPM_PACKAGE_REQUIRES "dkms, gcc, make, kernel-devel, perl")
|
||||
set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE "${PROJECT_SOURCE_DIR}/scripts/rpm/postinstall")
|
||||
set(CPACK_RPM_PRE_UNINSTALL_SCRIPT_FILE "${PROJECT_SOURCE_DIR}/scripts/rpm/preuninstall")
|
||||
set(CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE "${PROJECT_SOURCE_DIR}/scripts/rpm/postuninstall")
|
||||
set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION /usr/src /usr/share/man /usr/share/man/man8 /etc /usr /usr/bin /usr/share /etc/rc.d /etc/rc.d/init.d )
|
||||
set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION /usr/src /usr/share/man /usr/share/man/man8 /etc /usr /usr/bin /usr/share /etc/rc.d /etc/rc.d/init.d)
|
||||
set(CPACK_RPM_PACKAGE_RELOCATABLE "OFF")
|
||||
|
||||
include(CPack)
|
||||
|
||||
9
OWNERS
9
OWNERS
@@ -1,11 +1,12 @@
|
||||
approvers:
|
||||
- leodido
|
||||
- fntlnz
|
||||
- kris-nova
|
||||
- leodido
|
||||
- mstemm
|
||||
reviewers:
|
||||
- leodido
|
||||
- fntlnz
|
||||
- mfdii
|
||||
- kaizhe
|
||||
- kris-nova
|
||||
- leodido
|
||||
- mfdii
|
||||
- mstemm
|
||||
|
||||
|
||||
11
README.md
11
README.md
@@ -5,7 +5,7 @@
|
||||
|
||||
#### Latest release
|
||||
|
||||
**v0.15.2**
|
||||
**v0.17.0**
|
||||
Read the [change log](https://github.com/falcosecurity/falco/blob/dev/CHANGELOG.md)
|
||||
|
||||
Dev Branch: [](https://travis-ci.com/falcosecurity/falco)<br />
|
||||
@@ -45,10 +45,17 @@ See [Falco Documentation](https://falco.org/docs/) to quickly get started using
|
||||
|
||||
Join the Community
|
||||
---
|
||||
* [Join the mailing list](http://bit.ly/2Mu0wXA) for news and a Google calendar invite for our Falco open source meetings. Note: this is the only way to get a calendar invite for our open meetings.
|
||||
* [Website](https://falco.org) for Falco.
|
||||
* We are working on a blog for the Falco project. In the meantime you can find [Falco](https://sysdig.com/blog/tag/falco/) posts over on the Sysdig blog.
|
||||
* Join our [Public Slack](https://slack.sysdig.com) channel for open source Sysdig and Falco announcements and discussions.
|
||||
|
||||
Office hours
|
||||
---
|
||||
|
||||
Falco has bi-weekly office hour style meetings where we plan our work on the project. You can get a Google calendar invite by joining the mailing list. It will automatically be sent.
|
||||
|
||||
Wednesdays at 8am Pacific on [Zoom](https://sysdig.zoom.us/j/213235330).
|
||||
|
||||
License Terms
|
||||
---
|
||||
Falco is licensed to you under the [Apache 2.0](./COPYING) open source license.
|
||||
|
||||
175
cmake/modules/Catch.cmake
Normal file
175
cmake/modules/Catch.cmake
Normal file
@@ -0,0 +1,175 @@
|
||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
#[=======================================================================[.rst:
|
||||
Catch
|
||||
-----
|
||||
|
||||
This module defines a function to help use the Catch test framework.
|
||||
|
||||
The :command:`catch_discover_tests` discovers tests by asking the compiled test
|
||||
executable to enumerate its tests. This does not require CMake to be re-run
|
||||
when tests change. However, it may not work in a cross-compiling environment,
|
||||
and setting test properties is less convenient.
|
||||
|
||||
This command is intended to replace use of :command:`add_test` to register
|
||||
tests, and will create a separate CTest test for each Catch test case. Note
|
||||
that this is in some cases less efficient, as common set-up and tear-down logic
|
||||
cannot be shared by multiple test cases executing in the same instance.
|
||||
However, it provides more fine-grained pass/fail information to CTest, which is
|
||||
usually considered as more beneficial. By default, the CTest test name is the
|
||||
same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
|
||||
|
||||
.. command:: catch_discover_tests
|
||||
|
||||
Automatically add tests with CTest by querying the compiled test executable
|
||||
for available tests::
|
||||
|
||||
catch_discover_tests(target
|
||||
[TEST_SPEC arg1...]
|
||||
[EXTRA_ARGS arg1...]
|
||||
[WORKING_DIRECTORY dir]
|
||||
[TEST_PREFIX prefix]
|
||||
[TEST_SUFFIX suffix]
|
||||
[PROPERTIES name1 value1...]
|
||||
[TEST_LIST var]
|
||||
)
|
||||
|
||||
``catch_discover_tests`` sets up a post-build command on the test executable
|
||||
that generates the list of tests by parsing the output from running the test
|
||||
with the ``--list-test-names-only`` argument. This ensures that the full
|
||||
list of tests is obtained. Since test discovery occurs at build time, it is
|
||||
not necessary to re-run CMake when the list of tests changes.
|
||||
However, it requires that :prop_tgt:`CROSSCOMPILING_EMULATOR` is properly set
|
||||
in order to function in a cross-compiling environment.
|
||||
|
||||
Additionally, setting properties on tests is somewhat less convenient, since
|
||||
the tests are not available at CMake time. Additional test properties may be
|
||||
assigned to the set of tests as a whole using the ``PROPERTIES`` option. If
|
||||
more fine-grained test control is needed, custom content may be provided
|
||||
through an external CTest script using the :prop_dir:`TEST_INCLUDE_FILES`
|
||||
directory property. The set of discovered tests is made accessible to such a
|
||||
script via the ``<target>_TESTS`` variable.
|
||||
|
||||
The options are:
|
||||
|
||||
``target``
|
||||
Specifies the Catch executable, which must be a known CMake executable
|
||||
target. CMake will substitute the location of the built executable when
|
||||
running the test.
|
||||
|
||||
``TEST_SPEC arg1...``
|
||||
Specifies test cases, wildcarded test cases, tags and tag expressions to
|
||||
pass to the Catch executable with the ``--list-test-names-only`` argument.
|
||||
|
||||
``EXTRA_ARGS arg1...``
|
||||
Any extra arguments to pass on the command line to each test case.
|
||||
|
||||
``WORKING_DIRECTORY dir``
|
||||
Specifies the directory in which to run the discovered test cases. If this
|
||||
option is not provided, the current binary directory is used.
|
||||
|
||||
``TEST_PREFIX prefix``
|
||||
Specifies a ``prefix`` to be prepended to the name of each discovered test
|
||||
case. This can be useful when the same test executable is being used in
|
||||
multiple calls to ``catch_discover_tests()`` but with different
|
||||
``TEST_SPEC`` or ``EXTRA_ARGS``.
|
||||
|
||||
``TEST_SUFFIX suffix``
|
||||
Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of
|
||||
every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may
|
||||
be specified.
|
||||
|
||||
``PROPERTIES name1 value1...``
|
||||
Specifies additional properties to be set on all tests discovered by this
|
||||
invocation of ``catch_discover_tests``.
|
||||
|
||||
``TEST_LIST var``
|
||||
Make the list of tests available in the variable ``var``, rather than the
|
||||
default ``<target>_TESTS``. This can be useful when the same test
|
||||
executable is being used in multiple calls to ``catch_discover_tests()``.
|
||||
Note that this variable is only available in CTest.
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
function(catch_discover_tests TARGET)
|
||||
cmake_parse_arguments(
|
||||
""
|
||||
""
|
||||
"TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST"
|
||||
"TEST_SPEC;EXTRA_ARGS;PROPERTIES"
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
if(NOT _WORKING_DIRECTORY)
|
||||
set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
endif()
|
||||
if(NOT _TEST_LIST)
|
||||
set(_TEST_LIST ${TARGET}_TESTS)
|
||||
endif()
|
||||
|
||||
## Generate a unique name based on the extra arguments
|
||||
string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS}")
|
||||
string(SUBSTRING ${args_hash} 0 7 args_hash)
|
||||
|
||||
# Define rule to generate test list for aforementioned test executable
|
||||
set(ctest_include_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_include-${args_hash}.cmake")
|
||||
set(ctest_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_tests-${args_hash}.cmake")
|
||||
get_property(crosscompiling_emulator
|
||||
TARGET ${TARGET}
|
||||
PROPERTY CROSSCOMPILING_EMULATOR
|
||||
)
|
||||
add_custom_command(
|
||||
TARGET ${TARGET} POST_BUILD
|
||||
BYPRODUCTS "${ctest_tests_file}"
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-D "TEST_TARGET=${TARGET}"
|
||||
-D "TEST_EXECUTABLE=$<TARGET_FILE:${TARGET}>"
|
||||
-D "TEST_EXECUTOR=${crosscompiling_emulator}"
|
||||
-D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}"
|
||||
-D "TEST_SPEC=${_TEST_SPEC}"
|
||||
-D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}"
|
||||
-D "TEST_PROPERTIES=${_PROPERTIES}"
|
||||
-D "TEST_PREFIX=${_TEST_PREFIX}"
|
||||
-D "TEST_SUFFIX=${_TEST_SUFFIX}"
|
||||
-D "TEST_LIST=${_TEST_LIST}"
|
||||
-D "CTEST_FILE=${ctest_tests_file}"
|
||||
-P "${_CATCH_DISCOVER_TESTS_SCRIPT}"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
file(WRITE "${ctest_include_file}"
|
||||
"if(EXISTS \"${ctest_tests_file}\")\n"
|
||||
" include(\"${ctest_tests_file}\")\n"
|
||||
"else()\n"
|
||||
" add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n"
|
||||
"endif()\n"
|
||||
)
|
||||
|
||||
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0")
|
||||
# Add discovered tests to directory TEST_INCLUDE_FILES
|
||||
set_property(DIRECTORY
|
||||
APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}"
|
||||
)
|
||||
else()
|
||||
# Add discovered tests as directory TEST_INCLUDE_FILE if possible
|
||||
get_property(test_include_file_set DIRECTORY PROPERTY TEST_INCLUDE_FILE SET)
|
||||
if (NOT ${test_include_file_set})
|
||||
set_property(DIRECTORY
|
||||
PROPERTY TEST_INCLUDE_FILE "${ctest_include_file}"
|
||||
)
|
||||
else()
|
||||
message(FATAL_ERROR
|
||||
"Cannot set more than one TEST_INCLUDE_FILE"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endfunction()
|
||||
|
||||
###############################################################################
|
||||
|
||||
set(_CATCH_DISCOVER_TESTS_SCRIPT
|
||||
${CMAKE_CURRENT_LIST_DIR}/CatchAddTests.cmake
|
||||
)
|
||||
78
cmake/modules/CatchAddTests.cmake
Normal file
78
cmake/modules/CatchAddTests.cmake
Normal file
@@ -0,0 +1,78 @@
|
||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
set(prefix "${TEST_PREFIX}")
|
||||
set(suffix "${TEST_SUFFIX}")
|
||||
set(spec ${TEST_SPEC})
|
||||
set(extra_args ${TEST_EXTRA_ARGS})
|
||||
set(properties ${TEST_PROPERTIES})
|
||||
set(script)
|
||||
set(suite)
|
||||
set(tests)
|
||||
|
||||
function(add_command NAME)
|
||||
set(_args "")
|
||||
foreach(_arg ${ARGN})
|
||||
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
|
||||
set(_args "${_args} [==[${_arg}]==]") # form a bracket_argument
|
||||
else()
|
||||
set(_args "${_args} ${_arg}")
|
||||
endif()
|
||||
endforeach()
|
||||
set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Run test executable to get list of available tests
|
||||
if(NOT EXISTS "${TEST_EXECUTABLE}")
|
||||
message(FATAL_ERROR
|
||||
"Specified test executable '${TEST_EXECUTABLE}' does not exist"
|
||||
)
|
||||
endif()
|
||||
execute_process(
|
||||
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-test-names-only
|
||||
OUTPUT_VARIABLE output
|
||||
RESULT_VARIABLE result
|
||||
)
|
||||
# Catch --list-test-names-only reports the number of tests, so 0 is... surprising
|
||||
if(${result} EQUAL 0)
|
||||
message(WARNING
|
||||
"Test executable '${TEST_EXECUTABLE}' contains no tests!\n"
|
||||
)
|
||||
elseif(${result} LESS 0)
|
||||
message(FATAL_ERROR
|
||||
"Error running test executable '${TEST_EXECUTABLE}':\n"
|
||||
" Result: ${result}\n"
|
||||
" Output: ${output}\n"
|
||||
)
|
||||
endif()
|
||||
|
||||
string(REPLACE "\n" ";" output "${output}")
|
||||
|
||||
# Parse output
|
||||
foreach(line ${output})
|
||||
set(test ${line})
|
||||
# use escape commas to handle properly test cases with commans inside the name
|
||||
string(REPLACE "," "\\," test_name ${test})
|
||||
# ...and add to script
|
||||
add_command(add_test
|
||||
"${prefix}${test}${suffix}"
|
||||
${TEST_EXECUTOR}
|
||||
"${TEST_EXECUTABLE}"
|
||||
"${test_name}"
|
||||
${extra_args}
|
||||
)
|
||||
add_command(set_tests_properties
|
||||
"${prefix}${test}${suffix}"
|
||||
PROPERTIES
|
||||
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
|
||||
${properties}
|
||||
)
|
||||
list(APPEND tests "${prefix}${test}${suffix}")
|
||||
endforeach()
|
||||
|
||||
# Create a list of all discovered tests, which users may use to e.g. set
|
||||
# properties on the tests
|
||||
add_command(set ${TEST_LIST} ${tests})
|
||||
|
||||
# Write CTest script
|
||||
file(WRITE "${CTEST_FILE}" "${script}")
|
||||
39
cmake/modules/DownloadCatch.cmake
Normal file
39
cmake/modules/DownloadCatch.cmake
Normal file
@@ -0,0 +1,39 @@
|
||||
#
|
||||
# Copyright (C) 2016-2019 Draios Inc dba Sysdig.
|
||||
#
|
||||
# This file is part of falco .
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy of
|
||||
# the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations under
|
||||
# the License.
|
||||
#
|
||||
include(ExternalProject)
|
||||
|
||||
set(CATCH2_INCLUDE ${CMAKE_BINARY_DIR}/catch2-prefix/include)
|
||||
|
||||
set(CATCH_EXTERNAL_URL
|
||||
URL
|
||||
https://github.com/catchorg/catch2/archive/v2.9.1.tar.gz
|
||||
URL_HASH
|
||||
MD5=4980778888fed635bf191d8a86f9f89c)
|
||||
|
||||
ExternalProject_Add(
|
||||
catch2
|
||||
PREFIX ${CMAKE_BINARY_DIR}/catch2-prefix
|
||||
${CATCH_EXTERNAL_URL}
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND
|
||||
${CMAKE_COMMAND}
|
||||
-E
|
||||
copy
|
||||
${CMAKE_BINARY_DIR}/catch2-prefix/src/catch2/single_include/catch2/catch.hpp
|
||||
${CATCH2_INCLUDE}/catch.hpp)
|
||||
39
cmake/modules/DownloadFakeIt.cmake
Normal file
39
cmake/modules/DownloadFakeIt.cmake
Normal file
@@ -0,0 +1,39 @@
|
||||
#
|
||||
# Copyright (C) 2016-2019 Draios Inc dba Sysdig.
|
||||
#
|
||||
# This file is part of falco .
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy of
|
||||
# the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations under
|
||||
# the License.
|
||||
#
|
||||
include(ExternalProject)
|
||||
|
||||
set(FAKEIT_INCLUDE ${CMAKE_BINARY_DIR}/fakeit-prefix/include)
|
||||
|
||||
set(FAKEIT_EXTERNAL_URL
|
||||
URL
|
||||
https://github.com/eranpeer/fakeit/archive/2.0.5.tar.gz
|
||||
URL_HASH
|
||||
MD5=d3d21b909cebaea5b780af5500bf384e)
|
||||
|
||||
ExternalProject_Add(
|
||||
fakeit-external
|
||||
PREFIX ${CMAKE_BINARY_DIR}/fakeit-prefix
|
||||
${FAKEIT_EXTERNAL_URL}
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND
|
||||
${CMAKE_COMMAND}
|
||||
-E
|
||||
copy
|
||||
${CMAKE_BINARY_DIR}/fakeit-prefix/src/fakeit-external/single_header/catch/fakeit.hpp
|
||||
${FAKEIT_INCLUDE}/fakeit.hpp)
|
||||
168
cmake/modules/GetGitRevisionDescription.cmake
Normal file
168
cmake/modules/GetGitRevisionDescription.cmake
Normal file
@@ -0,0 +1,168 @@
|
||||
# - Returns a version string from Git
|
||||
#
|
||||
# These functions force a re-configure on each git commit so that you can
|
||||
# trust the values of the variables in your build system.
|
||||
#
|
||||
# get_git_head_revision(<refspecvar> <hashvar> [<additional arguments to git describe> ...])
|
||||
#
|
||||
# Returns the refspec and sha hash of the current head revision
|
||||
#
|
||||
# git_describe(<var> [<additional arguments to git describe> ...])
|
||||
#
|
||||
# Returns the results of git describe on the source tree, and adjusting
|
||||
# the output so that it tests false if an error occurs.
|
||||
#
|
||||
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
|
||||
#
|
||||
# Returns the results of git describe --exact-match on the source tree,
|
||||
# and adjusting the output so that it tests false if there was no exact
|
||||
# matching tag.
|
||||
#
|
||||
# git_local_changes(<var>)
|
||||
#
|
||||
# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes.
|
||||
# Uses the return code of "git diff-index --quiet HEAD --".
|
||||
# Does not regard untracked files.
|
||||
#
|
||||
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||
#
|
||||
# Original Author:
|
||||
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
||||
# http://academic.cleardefinition.com
|
||||
# Iowa State University HCI Graduate Program/VRAC
|
||||
#
|
||||
# Copyright Iowa State University 2009-2010.
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
if(__get_git_revision_description)
|
||||
return()
|
||||
endif()
|
||||
set(__get_git_revision_description YES)
|
||||
|
||||
# We must run the following at "include" time, not at function call time,
|
||||
# to find the path to this module rather than the path to a calling list file
|
||||
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
|
||||
|
||||
function(get_git_head_revision _refspecvar _hashvar)
|
||||
set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
|
||||
while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories
|
||||
set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}")
|
||||
get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH)
|
||||
if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT)
|
||||
# We have reached the root directory, we are not in git
|
||||
set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
|
||||
set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
|
||||
endwhile()
|
||||
# check if this is a submodule
|
||||
if(NOT IS_DIRECTORY ${GIT_DIR})
|
||||
file(READ ${GIT_DIR} submodule)
|
||||
string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule})
|
||||
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
|
||||
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE)
|
||||
endif()
|
||||
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
|
||||
if(NOT EXISTS "${GIT_DATA}")
|
||||
file(MAKE_DIRECTORY "${GIT_DATA}")
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${GIT_DIR}/HEAD")
|
||||
return()
|
||||
endif()
|
||||
set(HEAD_FILE "${GIT_DATA}/HEAD")
|
||||
configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY)
|
||||
|
||||
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
|
||||
"${GIT_DATA}/grabRef.cmake"
|
||||
@ONLY)
|
||||
include("${GIT_DATA}/grabRef.cmake")
|
||||
|
||||
set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE)
|
||||
set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(git_describe _var)
|
||||
if(NOT GIT_FOUND)
|
||||
find_package(Git QUIET)
|
||||
endif()
|
||||
get_git_head_revision(refspec hash)
|
||||
if(NOT GIT_FOUND)
|
||||
set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
if(NOT hash)
|
||||
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# TODO sanitize
|
||||
#if((${ARGN}" MATCHES "&&") OR
|
||||
# (ARGN MATCHES "||") OR
|
||||
# (ARGN MATCHES "\\;"))
|
||||
# message("Please report the following error to the project!")
|
||||
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
|
||||
#endif()
|
||||
|
||||
# message(STATUS "Arguments to execute_process: ${ARGN}")
|
||||
|
||||
execute_process(COMMAND
|
||||
"${GIT_EXECUTABLE}"
|
||||
describe
|
||||
${hash}
|
||||
${ARGN}
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
RESULT_VARIABLE
|
||||
res
|
||||
OUTPUT_VARIABLE
|
||||
out
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(NOT res EQUAL 0)
|
||||
set(out "${out}-${res}-NOTFOUND")
|
||||
endif()
|
||||
|
||||
set(${_var} "${out}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(git_get_exact_tag _var)
|
||||
git_describe(out --exact-match ${ARGN})
|
||||
set(${_var} "${out}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(git_local_changes _var)
|
||||
if(NOT GIT_FOUND)
|
||||
find_package(Git QUIET)
|
||||
endif()
|
||||
get_git_head_revision(refspec hash)
|
||||
if(NOT GIT_FOUND)
|
||||
set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
if(NOT hash)
|
||||
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND
|
||||
"${GIT_EXECUTABLE}"
|
||||
diff-index --quiet HEAD --
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
RESULT_VARIABLE
|
||||
res
|
||||
OUTPUT_VARIABLE
|
||||
out
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(res EQUAL 0)
|
||||
set(${_var} "CLEAN" PARENT_SCOPE)
|
||||
else()
|
||||
set(${_var} "DIRTY" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
41
cmake/modules/GetGitRevisionDescription.cmake.in
Normal file
41
cmake/modules/GetGitRevisionDescription.cmake.in
Normal file
@@ -0,0 +1,41 @@
|
||||
#
|
||||
# Internal file for GetGitRevisionDescription.cmake
|
||||
#
|
||||
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||
#
|
||||
# Original Author:
|
||||
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
||||
# http://academic.cleardefinition.com
|
||||
# Iowa State University HCI Graduate Program/VRAC
|
||||
#
|
||||
# Copyright Iowa State University 2009-2010.
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
set(HEAD_HASH)
|
||||
|
||||
file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
|
||||
|
||||
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
|
||||
if(HEAD_CONTENTS MATCHES "ref")
|
||||
# named branch
|
||||
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
|
||||
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
|
||||
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
|
||||
else()
|
||||
configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
|
||||
file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
|
||||
if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
|
||||
set(HEAD_HASH "${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
# detached HEAD
|
||||
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
|
||||
endif()
|
||||
|
||||
if(NOT HEAD_HASH)
|
||||
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
|
||||
string(STRIP "${HEAD_HASH}" HEAD_HASH)
|
||||
endif()
|
||||
@@ -1,52 +1,49 @@
|
||||
FROM centos:6
|
||||
FROM centos:7
|
||||
|
||||
ENV FALCO_VERSION 0.1.1dev
|
||||
ENV BUILD_TYPE Release
|
||||
ENV BUILD_DRIVER OFF
|
||||
ENV BUILD_BPF OFF
|
||||
ENV BUILD_WARNINGS_AS_ERRORS ON
|
||||
ENV MAKE_JOBS 4
|
||||
LABEL name="falcosecurity/falco-builder"
|
||||
LABEL usage="docker run -v $PWD/..:/source -v $PWD/build:/build falcosecurity/falco-builder cmake"
|
||||
LABEL maintainer="opensource@sysdig.com"
|
||||
|
||||
# copied from builder script
|
||||
RUN curl -o /etc/yum.repos.d/devtools-2.repo https://people.centos.org/tru/devtools-2/devtools-2.repo && \
|
||||
rpm -i http://mirror.pnl.gov/epel/6/i386/epel-release-6-8.noarch.rpm && \
|
||||
sed -e 's,$basearch,i386,' -e 's,$releasever\],$releasever-i686\],' /etc/yum.repos.d/devtools-2.repo > /etc/yum.repos.d/devtools-2-i686.repo && \
|
||||
yum -y install \
|
||||
createrepo \
|
||||
devtoolset-2-toolchain \
|
||||
dpkg \
|
||||
dpkg-devel \
|
||||
expect \
|
||||
gcc \
|
||||
gcc-c++ \
|
||||
git \
|
||||
glibc-static \
|
||||
libcurl-devel \
|
||||
make \
|
||||
curl \
|
||||
libcurl-devel \
|
||||
zlib-devel \
|
||||
pkg-config \
|
||||
rpm-build \
|
||||
unzip \
|
||||
wget \
|
||||
tar \
|
||||
autoconf \
|
||||
automake \
|
||||
libtool && \
|
||||
yum -y install \
|
||||
glibc-devel.i686 \
|
||||
devtoolset-2-libstdc++-devel.i686 \
|
||||
devtoolset-2-elfutils-libelf-devel && \
|
||||
yum clean all
|
||||
RUN curl -o docker.tgz https://get.docker.com/builds/Linux/x86_64/docker-1.11.0.tgz && \
|
||||
tar xfz docker.tgz docker/docker && \
|
||||
mv docker/docker /usr/local/bin/docker && \
|
||||
chmod +x /usr/local/bin/docker && \
|
||||
rm -fr docker.tgz docker/
|
||||
ARG BUILD_TYPE=release
|
||||
ARG BUILD_DRIVER=OFF
|
||||
ARG BUILD_BPF=OFF
|
||||
ARG BUILD_WARNINGS_AS_ERRORS=ON
|
||||
ARG MAKE_JOBS=4
|
||||
ARG FALCO_VERSION
|
||||
|
||||
# TEMPORARY until dependencies in CMakeLists.txt are fixed
|
||||
RUN yum -y install libyaml-devel
|
||||
COPY entrypoint.sh /
|
||||
ENV BUILD_TYPE=${BUILD_TYPE}
|
||||
ENV BUILD_DRIVER=${BUILD_DRIVER}
|
||||
ENV BUILD_BPF=${BUILD_BPF}
|
||||
ENV BUILD_WARNINGS_AS_ERRORS=${BUILD_WARNINGS_AS_ERRORS}
|
||||
ENV MAKE_JOBS=${MAKE_JOBS}
|
||||
ENV FALCO_VERSION=${FALCO_VERSION}
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
ARG DOCKER_VERSION=1.11.0
|
||||
ARG CMAKE_VERSION=3.5.0
|
||||
|
||||
RUN yum -y install centos-release-scl && \
|
||||
INSTALL_PKGS="devtoolset-7-gcc devtoolset-7-gcc-c++ devtoolset-7-toolchain devtoolset-7-libstdc++-devel devtoolset-7-elfutils-libelf-devel glibc-static autoconf automake libtool createrepo expect git which libcurl-devel zlib-devel rpm-build" && \
|
||||
yum -y install --setopt=tsflags=nodocs $INSTALL_PKGS && \
|
||||
rpm -V $INSTALL_PKGS
|
||||
|
||||
RUN source scl_source enable devtoolset-7 && \
|
||||
cd /tmp && \
|
||||
curl -L https://github.com/kitware/cmake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}.tar.gz | tar xz; \
|
||||
cd cmake-${CMAKE_VERSION} && \
|
||||
./bootstrap --system-curl && \
|
||||
make -j${MAKE_JOBS} && \
|
||||
make install && \
|
||||
rm -rf /tmp/cmake-${CMAKE_VERSION}
|
||||
|
||||
# fixme: deps needs a fix into CMakeLists.txt
|
||||
RUN yum -y install libyaml-devel && yum clean all -y
|
||||
|
||||
COPY ./root /
|
||||
|
||||
# DTS
|
||||
ENV BASH_ENV=/usr/bin/scl_enable \
|
||||
ENV=/usr/bin/scl_enable \
|
||||
PROMPT_COMMAND=". /usr/bin/scl_enable"
|
||||
|
||||
ENTRYPOINT ["entrypoint"]
|
||||
CMD ["usage"]
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
SOURCE_DIR=/source
|
||||
BUILD_DIR=/build
|
||||
TASK=${1:-all}
|
||||
|
||||
MANPATH=
|
||||
|
||||
. /opt/rh/devtoolset-2/enable
|
||||
|
||||
# Download and install cmake if not downloaded
|
||||
CMAKE_DIR=$BUILD_DIR/cmake
|
||||
if [ ! -e $CMAKE_DIR ]; then
|
||||
cd $BUILD_DIR
|
||||
mkdir -p $BUILD_DIR/cmake
|
||||
wget -nv https://s3.amazonaws.com/download.draios.com/dependencies/cmake-3.3.2.tar.gz
|
||||
tar -C $CMAKE_DIR --strip-components 1 -xzf cmake-3.3.2.tar.gz
|
||||
cd $CMAKE_DIR
|
||||
./bootstrap --system-curl
|
||||
make -j$MAKE_JOBS
|
||||
fi
|
||||
|
||||
if [ $TASK == "cmake" ]; then
|
||||
mkdir -p $BUILD_DIR/$BUILD_TYPE
|
||||
cd $BUILD_DIR/$BUILD_TYPE
|
||||
$CMAKE_DIR/bin/cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DFALCO_VERSION=$FALCO_VERSION -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_DRIVER=${BUILD_DRIVER} -DBUILD_BPF=${BUILD_BPF} -DBUILD_WARNINGS_AS_ERRORS=${BUILD_WARNINGS_AS_ERRORS} $SOURCE_DIR/falco
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ $TASK == "bash" ]; then
|
||||
exec /bin/bash
|
||||
fi
|
||||
|
||||
cd $BUILD_DIR/$BUILD_TYPE
|
||||
make -j$MAKE_JOBS $TASK
|
||||
|
||||
|
||||
|
||||
62
docker/builder/root/usr/bin/entrypoint
Executable file
62
docker/builder/root/usr/bin/entrypoint
Executable file
@@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
SOURCE_DIR=/source
|
||||
BUILD_DIR=/build
|
||||
CMD=${1:-usage}
|
||||
shift
|
||||
|
||||
# Build type can be "debug" or "release", fallbacks to "release" by default
|
||||
BUILD_TYPE=$(echo "$BUILD_TYPE" | tr "[:upper:]" "[:lower:]")
|
||||
DRAIOS_DEBUG_FLAGS=
|
||||
case "$BUILD_TYPE" in
|
||||
"debug")
|
||||
DRAIOS_DEBUG_FLAGS="-D_DEBUG -DNDEBUG"
|
||||
;;
|
||||
*)
|
||||
BUILD_TYPE="release"
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$CMD" in
|
||||
"cmake")
|
||||
# Check that source directory contains Falco and Sysdig
|
||||
if [ ! -d "$SOURCE_DIR/sysdig" ]; then
|
||||
echo "Missing sysdig source." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -d "$SOURCE_DIR/falco" ]; then
|
||||
echo "Missing falco source." >&2
|
||||
exit 1
|
||||
fi
|
||||
# Prepare build directory
|
||||
mkdir -p "$BUILD_DIR/$BUILD_TYPE"
|
||||
cd "$BUILD_DIR/$BUILD_TYPE"
|
||||
|
||||
cmake \
|
||||
-DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||
-DBUILD_DRIVER="$BUILD_DRIVER" \
|
||||
-DBUILD_BPF="$BUILD_BPF" \
|
||||
-DBUILD_WARNINGS_AS_ERRORS="$BUILD_WARNINGS_AS_ERRORS" \
|
||||
-DFALCO_VERSION="$FALCO_VERSION" \
|
||||
-DDRAIOS_DEBUG_FLAGS="$DRAIOS_DEBUG_FLAGS" \
|
||||
"$SOURCE_DIR/falco"
|
||||
exit "$(printf '%d\n' $?)"
|
||||
;;
|
||||
"bash")
|
||||
CMD=/bin/bash
|
||||
;& # fallthrough
|
||||
"usage")
|
||||
exec "$CMD" "$@"
|
||||
;;
|
||||
*)
|
||||
if [ ! -d "$BUILD_DIR/$BUILD_TYPE" ]; then
|
||||
echo "Missing $BUILD_DIR/$BUILD_TYPE directory: run cmake."
|
||||
exit 1
|
||||
fi
|
||||
cd "$BUILD_DIR/$BUILD_TYPE"
|
||||
make -j"$MAKE_JOBS" "$CMD"
|
||||
;;
|
||||
esac
|
||||
6
docker/builder/root/usr/bin/scl_enable
Executable file
6
docker/builder/root/usr/bin/scl_enable
Executable file
@@ -0,0 +1,6 @@
|
||||
# IMPORTANT: Do not add more content to this file unless you know what you are doing.
|
||||
# This file is sourced everytime the shell session is opened.
|
||||
#
|
||||
# This will make scl collection binaries work out of box.
|
||||
unset BASH_ENV PROMPT_COMMAND ENV
|
||||
source scl_source enable devtoolset-7
|
||||
51
docker/builder/root/usr/bin/usage
Executable file
51
docker/builder/root/usr/bin/usage
Executable file
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
gccversion=$(gcc --version | head -n1)
|
||||
cppversion=$(g++ -dM -E -x c++ /dev/null | grep -F __cplusplus | cut -d' ' -f3)
|
||||
cmakeversion=$(cmake --version | head -n1)
|
||||
|
||||
cat <<EOF
|
||||
Hello, this is the Falco builder container.
|
||||
|
||||
How to use.
|
||||
|
||||
The default commands for the Falco builder image reports usage and environment info.
|
||||
* docker run falcosecurity/falco-builder
|
||||
* docker run falcosecurity/falco-builder usage
|
||||
|
||||
It supports bash.
|
||||
* docker run -ti falcosecurity/falco-builder bash
|
||||
|
||||
To build Falco it needs:
|
||||
- a bind-mount on the source directory (ie., the directory containing falco and sysdig source as siblings)
|
||||
|
||||
Optionally, you can also bind-mount the build directory.
|
||||
So, you can execute it from the Falco root directory as follows.
|
||||
|
||||
* docker run -v $PWD/..:/source -v $PWD/build:/build falcosecurity/falco-builder cmake
|
||||
* docker run -v $PWD/..:/source -v $PWD/build:/build falcosecurity/falco-builder [<cmake-target-x>, ..., <cmake-target-y>]
|
||||
|
||||
Eg.,
|
||||
* docker run -v $PWD/..:/source -v $PWD/build:/build falcosecurity/falco-builder tests
|
||||
* docker run -v $PWD/..:/source -v $PWD/build:/build falcosecurity/falco-builder install
|
||||
|
||||
How to build.
|
||||
|
||||
* cd docker/builder && DOCKER_BUILDKIT=1 docker build -t falcosecurity/falco-builder .
|
||||
|
||||
In case you want to customise the builder at build time the following build arguments are provided:
|
||||
- BUILD_TYPE whether you want a "release" or "debug" build (defaults to "release").
|
||||
- BUILD_DRIVER whether to build the driver or not (defaults to "OFF")
|
||||
- BUILD_BPF whether to build the BPF driver or not (defaults to "OFF")
|
||||
- BUILD_WARNINGS_AS_ERRORS whether to intend warnings as errors or not (defaults to "ON")
|
||||
- MAKE_JOBS the number of jobs to use during make (defaults to "4")
|
||||
- FALCO_VERSION the version to label the build (built from git index in case it is missing)
|
||||
|
||||
It is possible to change these at runtime (in the container) since environment variables with the same names are provided, too.
|
||||
|
||||
Environment.
|
||||
|
||||
* ${gccversion}
|
||||
* cplusplus ${cppversion}
|
||||
* ${cmakeversion}
|
||||
EOF
|
||||
@@ -1,12 +1,12 @@
|
||||
FROM debian:unstable
|
||||
|
||||
LABEL maintainer="Sysdig <support@sysdig.com>"
|
||||
LABEL usage="docker run -i -t -v /var/run/docker.sock:/host/var/run/docker.sock -v /dev:/host/dev -v /proc:/host/proc:ro -v /boot:/host/boot:ro -v /lib/modules:/host/lib/modules:ro -v /usr:/host/usr:ro --name NAME IMAGE"
|
||||
LABEL maintainer="opensource@sysdig.com"
|
||||
|
||||
ARG FALCO_VERSION=0.1.1dev
|
||||
ARG FALCO_VERSION=
|
||||
RUN test -n FALCO_VERSION
|
||||
ENV FALCO_VERSION ${FALCO_VERSION}
|
||||
|
||||
LABEL RUN="docker run -i -t -v /var/run/docker.sock:/host/var/run/docker.sock -v /dev:/host/dev -v /proc:/host/proc:ro -v /boot:/host/boot:ro -v /lib/modules:/host/lib/modules:ro -v /usr:/host/usr:ro --name NAME IMAGE"
|
||||
|
||||
ENV SYSDIG_HOST_ROOT /host
|
||||
|
||||
ENV HOME /root
|
||||
@@ -16,22 +16,32 @@ RUN cp /etc/skel/.bashrc /root && cp /etc/skel/.profile /root
|
||||
ADD http://download.draios.com/apt-draios-priority /etc/apt/preferences.d/
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
bash-completion \
|
||||
bc \
|
||||
clang-7 \
|
||||
ca-certificates \
|
||||
curl \
|
||||
dkms \
|
||||
gnupg2 \
|
||||
gcc \
|
||||
jq \
|
||||
libc6-dev \
|
||||
libelf-dev \
|
||||
llvm-7 \
|
||||
netcat \
|
||||
xz-utils \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
bash-completion \
|
||||
bc \
|
||||
clang-7 \
|
||||
ca-certificates \
|
||||
curl \
|
||||
dkms \
|
||||
gnupg2 \
|
||||
gcc \
|
||||
jq \
|
||||
libc6-dev \
|
||||
libelf-dev \
|
||||
llvm-7 \
|
||||
netcat \
|
||||
xz-utils \
|
||||
libmpc3 \
|
||||
binutils \
|
||||
libgomp1 \
|
||||
libitm1 \
|
||||
libatomic1 \
|
||||
liblsan0 \
|
||||
libtsan0 \
|
||||
libmpx2 \
|
||||
libquadmath0 \
|
||||
libcc1-0 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# gcc 6 is no longer included in debian unstable, but we need it to
|
||||
# build kernel modules on the default debian-based ami used by
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
FROM centos:7
|
||||
FROM fedora:28
|
||||
|
||||
ENV FALCO_VERSION 0.1.1dev
|
||||
ENV BUILD_TYPE Release
|
||||
LABEL name="falcosecurity/falco-tester"
|
||||
LABEL usage="docker run -v /boot:/boot:ro -v /var/run/docker.sock:/var/run/docker.sock -v $PWD/..:/source -v $PWD/build:/build -e FALCO_VERSION=<current_falco_version> --name <name> falcosecurity/falco-tester test"
|
||||
LABEL maintainer="opensource@sysdig.com"
|
||||
|
||||
RUN yum -y install epel-release && \
|
||||
yum -y install \
|
||||
python-pip \
|
||||
docker \
|
||||
jq \
|
||||
unzip
|
||||
ENV FALCO_VERSION=
|
||||
ENV BUILD_TYPE=release
|
||||
|
||||
RUN pip install avocado-framework avocado-framework-plugin-varianter-yaml-to-mux
|
||||
RUN curl https://avocado-project.org/data/repos/avocado-fedora.repo -o /etc/yum.repos.d/avocado.repo && \
|
||||
dnf install -y docker findutils jq unzip python2-avocado python2-avocado-plugins-varianter-yaml-to-mux && dnf clean all
|
||||
|
||||
COPY entrypoint.sh /
|
||||
COPY ./root /
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
ENTRYPOINT ["entrypoint"]
|
||||
CMD ["usage"]
|
||||
@@ -1,24 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
SOURCE_DIR=/source
|
||||
BUILD_DIR=/build
|
||||
TASK=${1:-test}
|
||||
|
||||
if [ $TASK == "test" ]; then
|
||||
echo "Building local docker image falcosecurity/falco:test from latest debian package..."
|
||||
cp $BUILD_DIR/$BUILD_TYPE/falco*.deb $BUILD_DIR/$BUILD_TYPE/docker/local
|
||||
cd $BUILD_DIR/$BUILD_TYPE/docker/local && docker build --build-arg FALCO_VERSION=${FALCO_VERSION} -t falcosecurity/falco:test .
|
||||
|
||||
echo "Running regression tests"
|
||||
cd $SOURCE_DIR/falco/test
|
||||
bash run_regression_tests.sh $BUILD_DIR/$BUILD_TYPE
|
||||
|
||||
docker rmi falcosecurity/falco:test || true
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ $TASK == "bash" ]; then
|
||||
exec /bin/bash
|
||||
fi
|
||||
57
docker/tester/root/usr/bin/entrypoint
Executable file
57
docker/tester/root/usr/bin/entrypoint
Executable file
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
SOURCE_DIR=/source
|
||||
BUILD_DIR=/build
|
||||
CMD=${1:-test}
|
||||
shift
|
||||
|
||||
# Build type can be "debug" or "release", fallbacks to "release" by default
|
||||
BUILD_TYPE=$(echo "$BUILD_TYPE" | tr "[:upper:]" "[:lower:]")
|
||||
case "$BUILD_TYPE" in
|
||||
"debug")
|
||||
;;
|
||||
*)
|
||||
BUILD_TYPE="release"
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$CMD" in
|
||||
"test")
|
||||
if [ ! -d "$BUILD_DIR/$BUILD_TYPE/docker/local" ]; then
|
||||
echo "Missing $BUILD_DIR/$BUILD_TYPE/docker/local directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$FALCO_VERSION" ]; then
|
||||
echo "Missing Falco version." >&2
|
||||
exit 1
|
||||
fi
|
||||
PACKAGE="$BUILD_DIR/$BUILD_TYPE/falco-$FALCO_VERSION-x86_64.deb"
|
||||
if [ ! -f "$PACKAGE" ]; then
|
||||
echo "Package(s) not found." >&2
|
||||
exit 1
|
||||
fi
|
||||
DOCKER_IMAGE_NAME="falcosecurity/falco:test"
|
||||
echo "Building local docker image $DOCKER_IMAGE_NAME from latest debian package..."
|
||||
cp "$PACKAGE" $BUILD_DIR/$BUILD_TYPE/docker/local
|
||||
cd $BUILD_DIR/$BUILD_TYPE/docker/local
|
||||
docker build --build-arg FALCO_VERSION="$FALCO_VERSION" -t "$DOCKER_IMAGE_NAME" .
|
||||
|
||||
# Check that source directory contains Falco and Sysdig
|
||||
if [ ! -d "$SOURCE_DIR/falco/test" ]; then
|
||||
echo "Missing $SOURCE_DIR/falco/test directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Running regression tests ..."
|
||||
cd $SOURCE_DIR/falco/test
|
||||
bash run_regression_tests.sh $BUILD_DIR/$BUILD_TYPE
|
||||
docker rmi "$DOCKER_IMAGE_NAME" || true
|
||||
;;
|
||||
"bash")
|
||||
CMD=/bin/bash
|
||||
;& # fallthrough
|
||||
"usage")
|
||||
exec "$CMD" "$@"
|
||||
;;
|
||||
esac
|
||||
41
docker/tester/root/usr/bin/usage
Executable file
41
docker/tester/root/usr/bin/usage
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
pythonversion=$(python -c 'import sys; version=sys.version_info[:3]; print("{0}.{1}.{2}".format(*version))')
|
||||
pipversion=$(pip --version | cut -d' ' -f 1,2,5,6)
|
||||
dockerversion=$(docker --version)
|
||||
avocadoversion=$(pip show avocado-framework | grep Version)
|
||||
avocadoversion=${avocadoversion#"Version: "}
|
||||
|
||||
cat <<EOF
|
||||
Hello, this is the Falco tester container.
|
||||
|
||||
How to use.
|
||||
|
||||
The default commands for the Falco tester image reports usage and environment info.
|
||||
* docker run falcosecurity/falco-tester
|
||||
* docker run falcosecurity/falco-tester usage
|
||||
|
||||
It supports bash.
|
||||
* docker run -ti falcosecurity/falco-tester bash
|
||||
|
||||
To run Falco regression tests you need to provide:
|
||||
- the docker socket
|
||||
- the boot directory
|
||||
- the source directory
|
||||
- the directory where Falco has been built
|
||||
- the environment variable FALCO_VARIABLE set to the value obtained during the Falco's build
|
||||
|
||||
Assuming you are running it from the Falco root directory, you can run it as follows.
|
||||
* docker run -v /boot:/boot:ro -v /var/run/docker.sock:/var/run/docker.sock -v $PWD/..:/source -v $PWD/build:/build -e FALCO_VERSION=<current_falco_version> falcosecurity/falco-tester test
|
||||
|
||||
How to build.
|
||||
|
||||
* cd docker/builder && DOCKER_BUILDKIT=1 docker build -t falcosecurity/falco-tester .
|
||||
|
||||
Environment.
|
||||
|
||||
* python ${pythonversion}
|
||||
* ${pipversion}
|
||||
* avocado ${avocadoversion}
|
||||
* ${dockerversion}
|
||||
EOF
|
||||
23
falco.yaml
23
falco.yaml
@@ -80,7 +80,6 @@ buffered_outputs: false
|
||||
# The rate at which log/alert messages are emitted is governed by a
|
||||
# token bucket. The rate corresponds to one message every 30 seconds
|
||||
# with a burst of 10 messages.
|
||||
|
||||
syscall_event_drops:
|
||||
actions:
|
||||
- log
|
||||
@@ -88,6 +87,21 @@ syscall_event_drops:
|
||||
rate: .03333
|
||||
max_burst: 10
|
||||
|
||||
# Options to configure the kernel module check.
|
||||
# Falco uses a kernel module to obtain the info to match against the rules.
|
||||
# In order to correctly behave it needs to ensure that the kernel module is always present and well behaving.
|
||||
# The following options configure:
|
||||
# the frequency it should check for the kernel module
|
||||
# the maximum number of consecutive failures after which it should stop
|
||||
# the exponential backoff mechanism it have to use to check for the module and eventally to try to re-insert it automatically.
|
||||
module_check:
|
||||
frequency: 10
|
||||
max_consecutive_failures: 3
|
||||
backoff:
|
||||
max_attempts: 5
|
||||
init_delay: 100
|
||||
max_delay: 3000
|
||||
|
||||
# A throttling mechanism implemented as a token bucket limits the
|
||||
# rate of falco notifications. This throttling is controlled by the following configuration
|
||||
# options:
|
||||
@@ -99,14 +113,12 @@ syscall_event_drops:
|
||||
# an initial quiet period, and then up to 1 notification per second
|
||||
# afterward. It would gain the full burst back after 1000 seconds of
|
||||
# no activity.
|
||||
|
||||
outputs:
|
||||
rate: 1
|
||||
max_burst: 1000
|
||||
|
||||
# Where security notifications should go.
|
||||
# Multiple outputs can be enabled.
|
||||
|
||||
syslog_output:
|
||||
enabled: true
|
||||
|
||||
@@ -117,7 +129,6 @@ syslog_output:
|
||||
#
|
||||
# Also, the file will be closed and reopened if falco is signaled with
|
||||
# SIGUSR1.
|
||||
|
||||
file_output:
|
||||
enabled: false
|
||||
keep_alive: false
|
||||
@@ -136,7 +147,6 @@ stdout_output:
|
||||
# $ openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem
|
||||
# $ cat certificate.pem key.pem > falco.pem
|
||||
# $ sudo cp falco.pem /etc/falco/falco.pem
|
||||
|
||||
webserver:
|
||||
enabled: true
|
||||
listen_port: 8765
|
||||
@@ -166,5 +176,4 @@ program_output:
|
||||
|
||||
http_output:
|
||||
enabled: false
|
||||
url: http://some.url
|
||||
|
||||
url: http://some.url
|
||||
@@ -18,7 +18,7 @@ For running this integration you will need:
|
||||
|
||||
This integration uses the [same environment variables that anchore-cli](https://github.com/anchore/anchore-cli#configuring-the-anchore-cli):
|
||||
|
||||
* ANCHORE_CLI_USER: The user used to conect to anchore-engine. By default is ```admin```
|
||||
* ANCHORE_CLI_USER: The user used to connect to anchore-engine. By default is ```admin```
|
||||
* ANCHORE_CLI_PASS: The password used to connect to anchore-engine.
|
||||
* ANCHORE_CLI_URL: The url where anchore-engine listens. Make sure does not end with a slash. By default is ```http://localhost:8228/v1```
|
||||
* ANCHORE_CLI_SSL_VERIFY: Flag for enabling if HTTP client verifies SSL. By default is ```true```
|
||||
@@ -81,7 +81,7 @@ So you can run directly with Docker:
|
||||
|
||||
```
|
||||
docker run --rm -e ANCHORE_CLI_USER=<user-for-custom-anchore-engine> \
|
||||
-e ANCHORE_CLI_PASS=<passsword-for-user-for-custom-anchore-engine> \
|
||||
-e ANCHORE_CLI_PASS=<password-for-user-for-custom-anchore-engine> \
|
||||
-e ANCHORE_CLI_URL=http://<custom-anchore-engine-host>:8228/v1 \
|
||||
sysdig/anchore-falco
|
||||
```
|
||||
|
||||
@@ -29,7 +29,7 @@ service/falco-service created
|
||||
k8s-using-daemonset$
|
||||
```
|
||||
|
||||
The Daemon Set also relies on a Kubernetes ConfigMap to store the Falco configuration and make the configuration available to the Falco Pods. This allows you to manage custom configuration without rebuilding and redeploying the underlying Pods. In order to create the ConfigMap you'll need to first need to copy the required configuration from their location in this GitHub repo to the `k8s-with-rbac/falco-config/` directory (please note that you will need to create the /falco-config directory). Any modification of the configuration should be performed on these copies rather than the original files.
|
||||
The Daemon Set also relies on a Kubernetes ConfigMap to store the Falco configuration and make the configuration available to the Falco Pods. This allows you to manage custom configuration without rebuilding and redeploying the underlying Pods. In order to create the ConfigMap you'll first need to copy the required configuration from their location in this GitHub repo to the `k8s-with-rbac/falco-config/` directory (please note that you will need to create the /falco-config directory). Any modification of the configuration should be performed on these copies rather than the original files.
|
||||
|
||||
```
|
||||
k8s-using-daemonset$ mkdir -p k8s-with-rbac/falco-config
|
||||
@@ -59,8 +59,7 @@ Now that we have the requirements for our Daemon Set in place, we can create our
|
||||
|
||||
```
|
||||
k8s-using-daemonset$ kubectl create -f k8s-with-rbac/falco-daemonset-configmap.yaml
|
||||
daemonset.extensions "falco-daemonset" created
|
||||
|
||||
daemonset "falco" created
|
||||
k8s-using-daemonset$
|
||||
```
|
||||
|
||||
@@ -98,13 +97,14 @@ In order to test that Falco is working correctly, you can launch a shell in a Po
|
||||
|
||||
```
|
||||
k8s-using-daemonset$ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
falco-daemonset-b695d 1/1 Running 0 2d
|
||||
falco-daemonset-n8q2v 1/1 Running 0 2d
|
||||
k8s-using-daemonset$ kubectl exec -it falco-daemonset-b695d bash
|
||||
root@falco-daemonset-b695d:/# exit
|
||||
k8s-using-daemonset$ kubectl logs falco-daemonset-b695d
|
||||
07:16:09.217866519: Error File below known binary directory renamed/removed (user=root command=event_generator pcmdline=<NA> operation=rename file=<NA> res=0 oldpath=/bin/true newpath=/bin/true.event-generator-sh ) k8s.ns=default k8s.pod=falco-event-generator-deployment-645444689b-j6mth container=0e67aad65846 k8s.ns=default k8s.pod=falco-event-generator-deployment-645444689b-j6mth container=0e67aad65846
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
falco-74htl 1/1 Running 0 13h
|
||||
falco-fqz2m 1/1 Running 0 13h
|
||||
falco-sgjfx 1/1 Running 0 13h
|
||||
k8s-using-daemonset$ kubectl exec -it falco-74htl bash
|
||||
root@falco-74htl:/# exit
|
||||
k8s-using-daemonset$ kubectl logs falco-74htl
|
||||
{"output":"17:48:58.590038385: Notice A shell was spawned in a container with an attached terminal (user=root k8s.pod=falco-74htl container=a98c2aa8e670 shell=bash parent=<NA> cmdline=bash terminal=34816)","priority":"Notice","rule":"Terminal shell in container","time":"2017-12-20T17:48:58.590038385Z", "output_fields": {"container.id":"a98c2aa8e670","evt.time":1513792138590038385,"k8s.pod.name":"falco-74htl","proc.cmdline":"bash ","proc.name":"bash","proc.pname":null,"proc.tty":34816,"user.name":"root"}}
|
||||
k8s-using-daemonset$
|
||||
```
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
- macro: rename
|
||||
condition: evt.type in (rename, renameat)
|
||||
- macro: mkdir
|
||||
condition: evt.type = mkdir
|
||||
condition: evt.type in (mkdir, mkdirat)
|
||||
- macro: remove
|
||||
condition: evt.type in (rmdir, unlink, unlinkat)
|
||||
|
||||
@@ -72,6 +72,9 @@
|
||||
- macro: create_symlink
|
||||
condition: evt.type in (symlink, symlinkat) and evt.dir=<
|
||||
|
||||
- macro: chmod
|
||||
condition: (evt.type in (chmod, fchmod, fchmodat) and evt.dir=<)
|
||||
|
||||
# File categories
|
||||
- macro: bin_dir
|
||||
condition: fd.directory in (/bin, /sbin, /usr/bin, /usr/sbin)
|
||||
@@ -111,7 +114,7 @@
|
||||
items: [add-shell, remove-shell]
|
||||
|
||||
- macro: shell_procs
|
||||
condition: (proc.name in (shell_binaries))
|
||||
condition: proc.name in (shell_binaries)
|
||||
|
||||
- list: coreutils_binaries
|
||||
items: [
|
||||
@@ -159,7 +162,7 @@
|
||||
items: [docker, dockerd, exe, docker-compose, docker-entrypoi, docker-runc-cur, docker-current, dockerd-current]
|
||||
|
||||
- list: k8s_binaries
|
||||
items: [hyperkube, skydns, kube2sky, exechealthz, weave-net, loopback, bridge, openshift-sdn]
|
||||
items: [hyperkube, skydns, kube2sky, exechealthz, weave-net, loopback, bridge, openshift-sdn, openshift]
|
||||
|
||||
- list: lxd_binaries
|
||||
items: [lxd, lxcfs]
|
||||
@@ -243,7 +246,7 @@
|
||||
# A canonical set of processes that run other programs with different
|
||||
# privileges or as a different user.
|
||||
- list: userexec_binaries
|
||||
items: [sudo, su, suexec, critical-stack]
|
||||
items: [sudo, su, suexec, critical-stack, dzdo]
|
||||
|
||||
- list: known_setuid_binaries
|
||||
items: [
|
||||
@@ -311,13 +314,17 @@
|
||||
(fd.ip != "0.0.0.0" and fd.net != "127.0.0.0/8") and
|
||||
(evt.rawres >= 0 or evt.res = EINPROGRESS))
|
||||
|
||||
# RFC1918 addresses were assigned for private network usage
|
||||
- list: rfc_1918_addresses
|
||||
items: ['"10.0.0.0/8"', '"172.16.0.0/12"', '"192.168.0.0/16"']
|
||||
|
||||
- macro: outbound
|
||||
condition: >
|
||||
(((evt.type = connect and evt.dir=<) or
|
||||
(evt.type in (sendto,sendmsg) and evt.dir=< and
|
||||
fd.l4proto != tcp and fd.connected=false and fd.name_changed=true)) and
|
||||
(fd.typechar = 4 or fd.typechar = 6) and
|
||||
(fd.ip != "0.0.0.0" and fd.net != "127.0.0.0/8") and
|
||||
(fd.ip != "0.0.0.0" and fd.net != "127.0.0.0/8" and not fd.snet in (rfc_1918_addresses)) and
|
||||
(evt.rawres >= 0 or evt.res = EINPROGRESS))
|
||||
|
||||
# Very similar to inbound/outbound, but combines the tests together
|
||||
@@ -348,7 +355,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
|
||||
output: Disallowed SSH Connection (command=%proc.cmdline connection=%fd.name user=%user.name)
|
||||
output: Disallowed SSH Connection (command=%proc.cmdline connection=%fd.name user=%user.name container_id=%container.id image=%container.image.repository)
|
||||
priority: NOTICE
|
||||
tags: [network, mitre_remote_service]
|
||||
|
||||
@@ -379,7 +386,7 @@
|
||||
((fd.sip in (allowed_outbound_destination_ipaddrs)) or
|
||||
(fd.snet in (allowed_outbound_destination_networks)) or
|
||||
(fd.sip.name in (allowed_outbound_destination_domains)))
|
||||
output: Disallowed outbound connection destination (command=%proc.cmdline connection=%fd.name user=%user.name)
|
||||
output: Disallowed outbound connection destination (command=%proc.cmdline connection=%fd.name user=%user.name container_id=%container.id image=%container.image.repository)
|
||||
priority: NOTICE
|
||||
tags: [network]
|
||||
|
||||
@@ -402,7 +409,7 @@
|
||||
((fd.cip in (allowed_inbound_source_ipaddrs)) or
|
||||
(fd.cnet in (allowed_inbound_source_networks)) or
|
||||
(fd.cip.name in (allowed_inbound_source_domains)))
|
||||
output: Disallowed inbound connection source (command=%proc.cmdline connection=%fd.name user=%user.name)
|
||||
output: Disallowed inbound connection source (command=%proc.cmdline connection=%fd.name user=%user.name container_id=%container.id image=%container.image.repository)
|
||||
priority: NOTICE
|
||||
tags: [network]
|
||||
|
||||
@@ -440,7 +447,7 @@
|
||||
fd.directory in (shell_config_directories)) and
|
||||
not proc.name in (shell_binaries)
|
||||
output: >
|
||||
a shell configuration file has been modified (user=%user.name command=%proc.cmdline file=%fd.name)
|
||||
a shell configuration file has been modified (user=%user.name command=%proc.cmdline file=%fd.name container_id=%container.id image=%container.image.repository)
|
||||
priority:
|
||||
WARNING
|
||||
tag: [file, mitre_persistence]
|
||||
@@ -462,7 +469,7 @@
|
||||
fd.directory in (shell_config_directories)) and
|
||||
(not proc.name in (shell_binaries))
|
||||
output: >
|
||||
a shell configuration file was read by a non-shell program (user=%user.name command=%proc.cmdline file=%fd.name)
|
||||
a shell configuration file was read by a non-shell program (user=%user.name command=%proc.cmdline file=%fd.name container_id=%container.id image=%container.image.repository)
|
||||
priority:
|
||||
WARNING
|
||||
tag: [file, mitre_discovery]
|
||||
@@ -901,12 +908,15 @@
|
||||
- macro: access_repositories
|
||||
condition: (fd.filename in (repository_files) or fd.directory in (repository_directories))
|
||||
|
||||
- macro: modify_repositories
|
||||
condition: (evt.arg.newpath pmatch (repository_directories))
|
||||
|
||||
- rule: Update Package Repository
|
||||
desc: Detect package repositories get updated
|
||||
condition: >
|
||||
open_write and access_repositories and not package_mgmt_procs
|
||||
((open_write and access_repositories) or (modify and modify_repositories)) and not package_mgmt_procs
|
||||
output: >
|
||||
Repository files get updated (user=%user.name command=%proc.cmdline file=%fd.name)
|
||||
Repository files get updated (user=%user.name command=%proc.cmdline file=%fd.name newpath=%evt.arg.newpath container_id=%container.id image=%container.image.repository)
|
||||
priority:
|
||||
NOTICE
|
||||
tags: [filesystem, mitre_persistence]
|
||||
@@ -921,7 +931,7 @@
|
||||
and not python_running_ms_oms
|
||||
output: >
|
||||
File below a known binary directory opened for writing (user=%user.name
|
||||
command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline gparent=%proc.aname[2])
|
||||
command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline gparent=%proc.aname[2] container_id=%container.id image=%container.image.repository)
|
||||
priority: ERROR
|
||||
tags: [filesystem, mitre_persistence]
|
||||
|
||||
@@ -979,7 +989,7 @@
|
||||
and not user_known_write_monitored_dir_conditions
|
||||
output: >
|
||||
File below a monitored directory opened for writing (user=%user.name
|
||||
command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline gparent=%proc.aname[2])
|
||||
command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline gparent=%proc.aname[2] container_id=%container.id image=%container.image.repository)
|
||||
priority: ERROR
|
||||
tags: [filesystem, mitre_persistence]
|
||||
|
||||
@@ -998,7 +1008,7 @@
|
||||
(not proc.name in (ssh_binaries)))
|
||||
output: >
|
||||
ssh-related file/directory read by non-ssh program (user=%user.name
|
||||
command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline)
|
||||
command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline container_id=%container.id image=%container.image.repository)
|
||||
priority: ERROR
|
||||
tags: [filesystem, mitre_discovery]
|
||||
|
||||
@@ -1148,6 +1158,10 @@
|
||||
- macro: user_known_write_etc_conditions
|
||||
condition: proc.name=confd
|
||||
|
||||
# This is a placeholder for user to extend the whitelist for write below etc rule
|
||||
- macro: user_known_write_below_etc_activities
|
||||
condition: (never_true)
|
||||
|
||||
- macro: write_etc_common
|
||||
condition: >
|
||||
etc_dir and evt.dir = < and open_write
|
||||
@@ -1245,18 +1259,19 @@
|
||||
and not checkpoint_writing_state
|
||||
and not jboss_in_container_writing_passwd
|
||||
and not etcd_manager_updating_dns
|
||||
and not user_known_write_below_etc_activities
|
||||
|
||||
- rule: Write below etc
|
||||
desc: an attempt to write to any file below /etc
|
||||
condition: write_etc_common
|
||||
output: "File below /etc opened for writing (user=%user.name command=%proc.cmdline parent=%proc.pname pcmdline=%proc.pcmdline file=%fd.name program=%proc.name gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4])"
|
||||
output: "File below /etc opened for writing (user=%user.name command=%proc.cmdline parent=%proc.pname pcmdline=%proc.pcmdline file=%fd.name program=%proc.name gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4] container_id=%container.id image=%container.image.repository)"
|
||||
priority: ERROR
|
||||
tags: [filesystem, mitre_persistence]
|
||||
|
||||
- list: known_root_files
|
||||
items: [/root/.monit.state, /root/.auth_tokens, /root/.bash_history, /root/.ash_history, /root/.aws/credentials,
|
||||
/root/.viminfo.tmp, /root/.lesshst, /root/.bzr.log, /root/.gitconfig.lock, /root/.babel.json, /root/.localstack,
|
||||
/root/.node_repl_history, /root/.mongorc.js, /root/.dbshell, /root/.augeas/history, /root/.rnd, /root/.wget-hsts, /health]
|
||||
/root/.node_repl_history, /root/.mongorc.js, /root/.dbshell, /root/.augeas/history, /root/.rnd, /root/.wget-hsts, /health, /exec.fifo]
|
||||
|
||||
- list: known_root_directories
|
||||
items: [/root/.oracle_jre_usage, /root/.ssh, /root/.subversion, /root/.nami]
|
||||
@@ -1308,6 +1323,10 @@
|
||||
- macro: user_known_write_root_conditions
|
||||
condition: fd.name=/root/.bash_history
|
||||
|
||||
# This is a placeholder for user to extend the whitelist for write below root rule
|
||||
- macro: user_known_write_below_root_activities
|
||||
condition: (never_true)
|
||||
|
||||
- rule: Write below root
|
||||
desc: an attempt to write to any file directly below / or /root
|
||||
condition: >
|
||||
@@ -1329,7 +1348,8 @@
|
||||
and not rancher_writing_root
|
||||
and not known_root_conditions
|
||||
and not user_known_write_root_conditions
|
||||
output: "File below / or /root opened for writing (user=%user.name command=%proc.cmdline parent=%proc.pname file=%fd.name program=%proc.name)"
|
||||
and not user_known_write_below_root_activities
|
||||
output: "File below / or /root opened for writing (user=%user.name command=%proc.cmdline parent=%proc.pname file=%fd.name program=%proc.name container_id=%container.id image=%container.image.repository)"
|
||||
priority: ERROR
|
||||
tags: [filesystem, mitre_persistence]
|
||||
|
||||
@@ -1344,7 +1364,7 @@
|
||||
condition: sensitive_files and open_read and server_procs and not proc_is_new and proc.name!="sshd"
|
||||
output: >
|
||||
Sensitive file opened for reading by trusted program after startup (user=%user.name
|
||||
command=%proc.cmdline parent=%proc.pname file=%fd.name parent=%proc.pname gparent=%proc.aname[2])
|
||||
command=%proc.cmdline parent=%proc.pname file=%fd.name parent=%proc.pname gparent=%proc.aname[2] container_id=%container.id image=%container.image.repository)
|
||||
priority: WARNING
|
||||
tags: [filesystem, mitre_credential_access]
|
||||
|
||||
@@ -1394,10 +1414,16 @@
|
||||
and not runuser_reading_pam
|
||||
output: >
|
||||
Sensitive file opened for reading by non-trusted program (user=%user.name program=%proc.name
|
||||
command=%proc.cmdline file=%fd.name parent=%proc.pname gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4])
|
||||
command=%proc.cmdline file=%fd.name parent=%proc.pname gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4] container_id=%container.id image=%container.image.repository)
|
||||
priority: WARNING
|
||||
tags: [filesystem, mitre_credential_access, mitre_discovery]
|
||||
|
||||
- macro: amazon_linux_running_python_yum
|
||||
condition: >
|
||||
(proc.name = python and
|
||||
proc.pcmdline = "python -m amazon_linux_extras system_motd" and
|
||||
proc.cmdline startswith "python -c import yum;")
|
||||
|
||||
# Only let rpm-related programs write to the rpm database
|
||||
- rule: Write below rpm database
|
||||
desc: an attempt to write to the rpm database by any non-rpm related program
|
||||
@@ -1407,7 +1433,8 @@
|
||||
and not ansible_running_python
|
||||
and not python_running_chef
|
||||
and not exe_running_docker_save
|
||||
output: "Rpm database opened for writing by a non-rpm program (command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline)"
|
||||
and not amazon_linux_running_python_yum
|
||||
output: "Rpm database opened for writing by a non-rpm program (command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline container_id=%container.id image=%container.image.repository)"
|
||||
priority: ERROR
|
||||
tags: [filesystem, software_mgmt, mitre_persistence]
|
||||
|
||||
@@ -1442,7 +1469,7 @@
|
||||
and not postgres_running_wal_e
|
||||
output: >
|
||||
Database-related program spawned process other than itself (user=%user.name
|
||||
program=%proc.cmdline parent=%proc.pname)
|
||||
program=%proc.cmdline parent=%proc.pname container_id=%container.id image=%container.image.repository)
|
||||
priority: NOTICE
|
||||
tags: [process, database, mitre_execution]
|
||||
|
||||
@@ -1451,7 +1478,7 @@
|
||||
condition: (bin_dir_rename) and modify and not package_mgmt_procs and not exe_running_docker_save
|
||||
output: >
|
||||
File below known binary directory renamed/removed (user=%user.name command=%proc.cmdline
|
||||
pcmdline=%proc.pcmdline operation=%evt.type file=%fd.name %evt.args)
|
||||
pcmdline=%proc.pcmdline operation=%evt.type file=%fd.name %evt.args container_id=%container.id image=%container.image.repository)
|
||||
priority: ERROR
|
||||
tags: [filesystem, mitre_persistence]
|
||||
|
||||
@@ -1460,7 +1487,7 @@
|
||||
condition: mkdir and bin_dir_mkdir and not package_mgmt_procs
|
||||
output: >
|
||||
Directory below known binary directory created (user=%user.name
|
||||
command=%proc.cmdline directory=%evt.arg.path)
|
||||
command=%proc.cmdline directory=%evt.arg.path container_id=%container.id image=%container.image.repository)
|
||||
priority: ERROR
|
||||
tags: [filesystem, mitre_persistence]
|
||||
|
||||
@@ -1470,6 +1497,18 @@
|
||||
- list: user_known_change_thread_namespace_binaries
|
||||
items: []
|
||||
|
||||
- macro: user_known_change_thread_namespace_activities
|
||||
condition: (never_true)
|
||||
|
||||
- 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)
|
||||
|
||||
- rule: Change thread namespace
|
||||
desc: >
|
||||
an attempt to change a program/thread\'s namespace (commonly done
|
||||
@@ -1477,7 +1516,7 @@
|
||||
condition: >
|
||||
evt.type = setns
|
||||
and not proc.name in (docker_binaries, k8s_binaries, lxd_binaries, sysdigcloud_binaries,
|
||||
sysdig, nsenter, calico, oci-umount)
|
||||
sysdig, nsenter, calico, oci-umount, network_plugin_binaries)
|
||||
and not proc.name in (user_known_change_thread_namespace_binaries)
|
||||
and not proc.name startswith "runc"
|
||||
and not proc.cmdline startswith "containerd"
|
||||
@@ -1487,9 +1526,12 @@
|
||||
and not kubelet_running_loopback
|
||||
and not rancher_agent
|
||||
and not rancher_network_manager
|
||||
and not calico_node
|
||||
and not weaveworks_scope
|
||||
and not user_known_change_thread_namespace_activities
|
||||
output: >
|
||||
Namespace change (setns) by unexpected program (user=%user.name command=%proc.cmdline
|
||||
parent=%proc.pname %container.info)
|
||||
parent=%proc.pname %container.info container_id=%container.id image=%container.image.repository)
|
||||
priority: NOTICE
|
||||
tags: [process]
|
||||
|
||||
@@ -1635,35 +1677,38 @@
|
||||
output: >
|
||||
Shell spawned by untrusted binary (user=%user.name shell=%proc.name parent=%proc.pname
|
||||
cmdline=%proc.cmdline pcmdline=%proc.pcmdline gparent=%proc.aname[2] ggparent=%proc.aname[3]
|
||||
aname[4]=%proc.aname[4] aname[5]=%proc.aname[5] aname[6]=%proc.aname[6] aname[7]=%proc.aname[7])
|
||||
aname[4]=%proc.aname[4] aname[5]=%proc.aname[5] aname[6]=%proc.aname[6] aname[7]=%proc.aname[7] container_id=%container.id image=%container.image.repository)
|
||||
priority: DEBUG
|
||||
tags: [shell, mitre_execution]
|
||||
|
||||
- macro: allowed_openshift_registry_root
|
||||
condition: >
|
||||
(container.image.repository startswith openshift3/ or
|
||||
container.image.repository startswith registry.redhat.io/openshift3/ or
|
||||
container.image.repository startswith registry.access.redhat.com/openshift3/)
|
||||
|
||||
# Source: https://docs.openshift.com/enterprise/3.2/install_config/install/disconnected_install.html
|
||||
- macro: openshift_image
|
||||
condition: >
|
||||
(allowed_openshift_registry_root and
|
||||
(container.image.repository contains logging-deployment or
|
||||
container.image.repository contains logging-elasticsearch or
|
||||
container.image.repository contains logging-kibana or
|
||||
container.image.repository contains logging-fluentd or
|
||||
container.image.repository contains logging-auth-proxy or
|
||||
container.image.repository contains metrics-deployer or
|
||||
container.image.repository contains metrics-hawkular-metrics or
|
||||
container.image.repository contains metrics-cassandra or
|
||||
container.image.repository contains metrics-heapster or
|
||||
container.image.repository contains ose-haproxy-router or
|
||||
container.image.repository contains ose-deployer or
|
||||
container.image.repository contains ose-sti-builder or
|
||||
container.image.repository contains ose-docker-builder or
|
||||
container.image.repository contains ose-pod or
|
||||
container.image.repository contains ose-docker-registry or
|
||||
container.image.repository contains image-inspector))
|
||||
(container.image.repository endswith /logging-deployment or
|
||||
container.image.repository endswith /logging-elasticsearch or
|
||||
container.image.repository endswith /logging-kibana or
|
||||
container.image.repository endswith /logging-fluentd or
|
||||
container.image.repository endswith /logging-auth-proxy or
|
||||
container.image.repository endswith /metrics-deployer or
|
||||
container.image.repository endswith /metrics-hawkular-metrics or
|
||||
container.image.repository endswith /metrics-cassandra or
|
||||
container.image.repository endswith /metrics-heapster or
|
||||
container.image.repository endswith /ose-haproxy-router or
|
||||
container.image.repository endswith /ose-deployer or
|
||||
container.image.repository endswith /ose-sti-builder or
|
||||
container.image.repository endswith /ose-docker-builder or
|
||||
container.image.repository endswith /ose-pod or
|
||||
container.image.repository endswith /ose-node or
|
||||
container.image.repository endswith /ose-docker-registry or
|
||||
container.image.repository endswith /prometheus-node-exporter or
|
||||
container.image.repository endswith /image-inspector))
|
||||
|
||||
# These images are allowed both to run with --privileged and to mount
|
||||
# sensitive paths from the host filesystem.
|
||||
@@ -1675,6 +1720,13 @@
|
||||
- list: trusted_images
|
||||
items: []
|
||||
|
||||
# NOTE: This macro is only provided for backwards compatibility with
|
||||
# older local falco rules files that may have been appending to
|
||||
# trusted_images. To make customizations, it's better to add containers to
|
||||
# user_trusted_containers, user_privileged_containers or user_sensitive_mount_containers.
|
||||
- macro: trusted_containers
|
||||
condition: (container.image.repository in (trusted_images))
|
||||
|
||||
# Add conditions to this macro (probably in a separate file,
|
||||
# overwriting this macro) to specify additional containers that are
|
||||
# trusted and therefore allowed to run privileged *and* with sensitive
|
||||
@@ -1687,10 +1739,10 @@
|
||||
# In this file, it just takes one of the images in trusted_containers
|
||||
# and repeats it.
|
||||
- macro: user_trusted_containers
|
||||
condition: (container.image.repository=sysdig/agent)
|
||||
condition: (container.image.repository endswith sysdig/agent)
|
||||
|
||||
- list: sematext_images
|
||||
items: [sematext/sematext-agent-docker, sematext/agent, sematext/logagent,
|
||||
items: [docker.io/sematext/sematext-agent-docker, docker.io/sematext/agent, docker.io/sematext/logagent,
|
||||
registry.access.redhat.com/sematext/sematext-agent-docker,
|
||||
registry.access.redhat.com/sematext/agent,
|
||||
registry.access.redhat.com/sematext/logagent]
|
||||
@@ -1698,10 +1750,10 @@
|
||||
# These container images are allowed to run with --privileged
|
||||
- list: falco_privileged_images
|
||||
items: [
|
||||
sysdig/agent, sysdig/falco, sysdig/sysdig,
|
||||
gcr.io/google_containers/kube-proxy, calico/node,
|
||||
rook/toolbox, cloudnativelabs/kube-router, mesosphere/mesos-slave,
|
||||
docker/ucp-agent, sematext_images
|
||||
docker.io/sysdig/agent, docker.io/sysdig/falco, docker.io/sysdig/sysdig,
|
||||
gcr.io/google_containers/kube-proxy, docker.io/calico/node,
|
||||
docker.io/rook/toolbox, docker.io/cloudnativelabs/kube-router, docker.io/mesosphere/mesos-slave,
|
||||
docker.io/docker/ucp-agent, sematext_images, k8s.gcr.io/kube-proxy
|
||||
]
|
||||
|
||||
- macro: falco_privileged_containers
|
||||
@@ -1719,8 +1771,7 @@
|
||||
# In this file, it just takes one of the images in falco_privileged_images
|
||||
# and repeats it.
|
||||
- macro: user_privileged_containers
|
||||
condition: (container.image.repository=sysdig/agent)
|
||||
|
||||
condition: (container.image.repository endswith sysdig/agent)
|
||||
|
||||
- list: rancher_images
|
||||
items: [
|
||||
@@ -1732,11 +1783,12 @@
|
||||
# host filesystem.
|
||||
- list: falco_sensitive_mount_images
|
||||
items: [
|
||||
sysdig/agent, sysdig/falco, sysdig/sysdig,
|
||||
docker.io/sysdig/agent, docker.io/sysdig/falco, docker.io/sysdig/sysdig,
|
||||
gcr.io/google_containers/hyperkube,
|
||||
gcr.io/google_containers/kube-proxy, calico/node,
|
||||
rook/toolbox, cloudnativelabs/kube-router, consul,
|
||||
datadog/docker-dd-agent, datadog/agent, docker/ucp-agent, gliderlabs/logspout
|
||||
gcr.io/google_containers/kube-proxy, docker.io/calico/node,
|
||||
docker.io/rook/toolbox, docker.io/cloudnativelabs/kube-router, docker.io/consul,
|
||||
docker.io/datadog/docker-dd-agent, docker.io/datadog/agent, docker.io/docker/ucp-agent, docker.io/gliderlabs/logspout,
|
||||
docker.io/netdata/netdata, docker.io/google/cadvisor, docker.io/prom/node-exporter
|
||||
]
|
||||
|
||||
- macro: falco_sensitive_mount_containers
|
||||
@@ -1756,7 +1808,7 @@
|
||||
# In this file, it just takes one of the images in falco_sensitive_mount_images
|
||||
# and repeats it.
|
||||
- macro: user_sensitive_mount_containers
|
||||
condition: (container.image.repository=sysdig/agent)
|
||||
condition: (container.image.repository = docker.io/sysdig/agent)
|
||||
|
||||
- rule: Launch Privileged Container
|
||||
desc: Detect the initial process started in a privileged container. Exceptions are made for known trusted images.
|
||||
@@ -1794,7 +1846,7 @@
|
||||
# when we lose events and lose track of state.
|
||||
|
||||
- macro: container_entrypoint
|
||||
condition: (not proc.pname exists or proc.pname in (runc:[0:PARENT], runc:[1:CHILD], docker-runc, exe))
|
||||
condition: (not proc.pname exists or proc.pname in (runc:[0:PARENT], runc:[1:CHILD], runc, docker-runc, exe))
|
||||
|
||||
- rule: Launch Sensitive Mount Container
|
||||
desc: >
|
||||
@@ -1837,7 +1889,7 @@
|
||||
- rule: System user interactive
|
||||
desc: an attempt to run interactive commands by a system (i.e. non-login) user
|
||||
condition: spawned_process and system_users and interactive
|
||||
output: "System user ran an interactive command (user=%user.name command=%proc.cmdline)"
|
||||
output: "System user ran an interactive command (user=%user.name command=%proc.cmdline container_id=%container.id image=%container.image.repository)"
|
||||
priority: INFO
|
||||
tags: [users, mitre_remote_access_tools]
|
||||
|
||||
@@ -1849,7 +1901,7 @@
|
||||
and container_entrypoint
|
||||
output: >
|
||||
A shell was spawned in a container with an attached terminal (user=%user.name %container.info
|
||||
shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline terminal=%proc.tty)
|
||||
shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline terminal=%proc.tty container_id=%container.id image=%container.image.repository)
|
||||
priority: NOTICE
|
||||
tags: [container, shell, mitre_execution]
|
||||
|
||||
@@ -1923,7 +1975,7 @@
|
||||
and not login_doing_dns_lookup
|
||||
output: >
|
||||
Known system binary sent/received network traffic
|
||||
(user=%user.name command=%proc.cmdline connection=%fd.name)
|
||||
(user=%user.name command=%proc.cmdline connection=%fd.name container_id=%container.id image=%container.image.repository)
|
||||
priority: NOTICE
|
||||
tags: [network, mitre_exfiltration]
|
||||
|
||||
@@ -1949,7 +2001,7 @@
|
||||
proc.env icontains HTTP_PROXY
|
||||
output: >
|
||||
Program run with disallowed HTTP_PROXY environment variable
|
||||
(user=%user.name command=%proc.cmdline env=%proc.env parent=%proc.pname)
|
||||
(user=%user.name command=%proc.cmdline env=%proc.env parent=%proc.pname container_id=%container.id image=%container.image.repository)
|
||||
priority: NOTICE
|
||||
tags: [host, users]
|
||||
|
||||
@@ -1972,7 +2024,7 @@
|
||||
and interpreted_procs)
|
||||
output: >
|
||||
Interpreted program received/listened for network traffic
|
||||
(user=%user.name command=%proc.cmdline connection=%fd.name)
|
||||
(user=%user.name command=%proc.cmdline connection=%fd.name container_id=%container.id image=%container.image.repository)
|
||||
priority: NOTICE
|
||||
tags: [network, mitre_exfiltration]
|
||||
|
||||
@@ -1983,7 +2035,7 @@
|
||||
and interpreted_procs)
|
||||
output: >
|
||||
Interpreted program performed outgoing network connection
|
||||
(user=%user.name command=%proc.cmdline connection=%fd.name)
|
||||
(user=%user.name command=%proc.cmdline connection=%fd.name container_id=%container.id image=%container.image.repository)
|
||||
priority: NOTICE
|
||||
tags: [network, mitre_exfiltration]
|
||||
|
||||
@@ -2024,7 +2076,7 @@
|
||||
condition: (inbound_outbound) and do_unexpected_udp_check and fd.l4proto=udp and not expected_udp_traffic
|
||||
output: >
|
||||
Unexpected UDP Traffic Seen
|
||||
(user=%user.name command=%proc.cmdline connection=%fd.name proto=%fd.l4proto evt=%evt.type %evt.args)
|
||||
(user=%user.name command=%proc.cmdline connection=%fd.name proto=%fd.l4proto evt=%evt.type %evt.args container_id=%container.id image=%container.image.repository)
|
||||
priority: NOTICE
|
||||
tags: [network, mitre_exfiltration]
|
||||
|
||||
@@ -2084,7 +2136,7 @@
|
||||
and not user_known_non_sudo_setuid_conditions
|
||||
output: >
|
||||
Unexpected setuid call by non-sudo, non-root program (user=%user.name cur_uid=%user.uid parent=%proc.pname
|
||||
command=%proc.cmdline uid=%evt.arg.uid)
|
||||
command=%proc.cmdline uid=%evt.arg.uid container_id=%container.id image=%container.image.repository)
|
||||
priority: NOTICE
|
||||
tags: [users, mitre_privilege_escalation]
|
||||
|
||||
@@ -2128,7 +2180,7 @@
|
||||
and not proc.name in (dev_creation_binaries)
|
||||
and not fd.name in (allowed_dev_files)
|
||||
and not fd.name startswith /dev/tty
|
||||
output: "File created below /dev by untrusted program (user=%user.name command=%proc.cmdline file=%fd.name)"
|
||||
output: "File created below /dev by untrusted program (user=%user.name command=%proc.cmdline file=%fd.name container_id=%container.id image=%container.image.repository)"
|
||||
priority: ERROR
|
||||
tags: [filesystem, mitre_persistence]
|
||||
|
||||
@@ -2189,7 +2241,7 @@
|
||||
- rule: Unexpected K8s NodePort Connection
|
||||
desc: Detect attempts to use K8s NodePorts from a container
|
||||
condition: (inbound_outbound) and fd.sport >= 30000 and fd.sport <= 32767 and container and not nodeport_containers
|
||||
output: Unexpected K8s NodePort Connection (command=%proc.cmdline connection=%fd.name)
|
||||
output: Unexpected K8s NodePort Connection (command=%proc.cmdline connection=%fd.name container_id=%container.id image=%container.image.repository)
|
||||
priority: NOTICE
|
||||
tags: [network, k8s, container, mitre_port_knocking]
|
||||
|
||||
@@ -2215,7 +2267,7 @@
|
||||
condition: >
|
||||
spawned_process and container and
|
||||
((proc.name = "nc" and (proc.args contains "-e" or proc.args contains "-c")) or
|
||||
(proc.name = "ncat" and (proc.args contains "--sh-exec" or proc.args contains "--exec" or proc.args contains "-e "
|
||||
(proc.name = "ncat" and (proc.args contains "--sh-exec" or proc.args contains "--exec" or proc.args contains "-e "
|
||||
or proc.args contains "-c " or proc.args contains "--lua-exec"))
|
||||
)
|
||||
output: >
|
||||
@@ -2299,12 +2351,23 @@
|
||||
- macro: access_log_files
|
||||
condition: (fd.directory in (log_directories) or fd.filename in (log_files))
|
||||
|
||||
# a placeholder for whitelist log files that could be cleared. Recommend the macro as (fd.name startswith "/var/log/app1*")
|
||||
- macro: allowed_clear_log_files
|
||||
condition: (never_true)
|
||||
|
||||
- macro: trusted_logging_images
|
||||
condition: (container.image.repository endswith "splunk/fluentd-hec")
|
||||
|
||||
- rule: Clear Log Activities
|
||||
desc: Detect clearing of critical log files
|
||||
condition: >
|
||||
open_write and access_log_files and evt.arg.flags contains "O_TRUNC"
|
||||
open_write and
|
||||
access_log_files and
|
||||
evt.arg.flags contains "O_TRUNC" and
|
||||
not trusted_logging_images and
|
||||
not allowed_clear_log_files
|
||||
output: >
|
||||
Log files were tampered (user=%user.name command=%proc.cmdline file=%fd.name)
|
||||
Log files were tampered (user=%user.name command=%proc.cmdline file=%fd.name container_id=%container.id image=%container.image.repository)
|
||||
priority:
|
||||
WARNING
|
||||
tags: [file, mitre_defense_evasion]
|
||||
@@ -2319,34 +2382,53 @@
|
||||
desc: Detect process running to clear bulk data from disk
|
||||
condition: spawned_process and clear_data_procs
|
||||
output: >
|
||||
Bulk data has been removed from disk (user=%user.name command=%proc.cmdline file=%fd.name)
|
||||
Bulk data has been removed from disk (user=%user.name command=%proc.cmdline file=%fd.name container_id=%container.id image=%container.image.repository)
|
||||
priority:
|
||||
WARNING
|
||||
tags: [process, mitre_persistence]
|
||||
|
||||
- rule: Delete Bash History
|
||||
desc: Detect bash history deletion
|
||||
- rule: Delete or rename shell history
|
||||
desc: Detect shell history deletion
|
||||
condition: >
|
||||
((spawned_process and proc.name in (shred, rm, mv) and proc.args contains "bash_history") or
|
||||
(open_write and fd.name contains "bash_history" and evt.arg.flags contains "O_TRUNC"))
|
||||
(modify and (
|
||||
evt.arg.name contains "bash_history" or
|
||||
evt.arg.name contains "zsh_history" or
|
||||
evt.arg.name contains "fish_read_history" or
|
||||
evt.arg.name endswith "fish_history" or
|
||||
evt.arg.oldpath contains "bash_history" or
|
||||
evt.arg.oldpath contains "zsh_history" or
|
||||
evt.arg.oldpath contains "fish_read_history" or
|
||||
evt.arg.oldpath endswith "fish_history" or
|
||||
evt.arg.path contains "bash_history" or
|
||||
evt.arg.path contains "zsh_history" or
|
||||
evt.arg.path contains "fish_read_history" or
|
||||
evt.arg.path endswith "fish_history")) or
|
||||
(open_write and (
|
||||
fd.name contains "bash_history" or
|
||||
fd.name contains "zsh_history" or
|
||||
fd.name contains "fish_read_history" or
|
||||
fd.name endswith "fish_history") and evt.arg.flags contains "O_TRUNC")
|
||||
output: >
|
||||
Bash history has been deleted (user=%user.name command=%proc.cmdline file=%fd.name %container.info)
|
||||
Shell history had been deleted or renamed (user=%user.name type=%evt.type command=%proc.cmdline fd.name=%fd.name name=%evt.arg.name path=%evt.arg.path oldpath=%evt.arg.oldpath %container.info)
|
||||
priority:
|
||||
WARNING
|
||||
tag: [process, mitre_defense_evation]
|
||||
|
||||
- macro: consider_all_chmods
|
||||
condition: (never_true)
|
||||
condition: (always_true)
|
||||
|
||||
- list: user_known_chmod_applications
|
||||
items: []
|
||||
|
||||
- rule: Set Setuid or Setgid bit
|
||||
desc: >
|
||||
When the setuid or setgid bits are set for an application,
|
||||
this means that the application will run with the privileges of the owning user or group respectively.
|
||||
Detect setuid or setgid bits set via chmod
|
||||
condition: consider_all_chmods and spawned_process and proc.name = "chmod" and (proc.args contains "+s" or proc.args contains "4777")
|
||||
condition: consider_all_chmods and chmod and (evt.arg.mode contains "S_ISUID" or evt.arg.mode contains "S_ISGID") and not proc.cmdline in (user_known_chmod_applications)
|
||||
output: >
|
||||
Setuid or setgid bit is set via chmod (user=%user.name command=%proc.cmdline
|
||||
container_id=%container.id container_name=%container.name image=%container.image.repository:%container.image.tag)
|
||||
Setuid or setgid bit is set via chmod (fd=%evt.arg.fd filename=%evt.arg.filename mode=%evt.arg.mode user=%user.name
|
||||
command=%proc.cmdline container_id=%container.id container_name=%container.name image=%container.image.repository:%container.image.tag)
|
||||
priority:
|
||||
NOTICE
|
||||
tag: [process, mitre_persistence]
|
||||
@@ -2361,12 +2443,14 @@
|
||||
- rule: Create Hidden Files or Directories
|
||||
desc: Detect hidden files or directories created
|
||||
condition: >
|
||||
((mkdir and consider_hidden_file_creation and evt.arg.path contains "/.") or
|
||||
(open_write and consider_hidden_file_creation and evt.arg.flags contains "O_CREAT" and
|
||||
fd.name contains "/." and not fd.name pmatch (exclude_hidden_directories)))
|
||||
(consider_hidden_file_creation and (
|
||||
(modify and evt.arg.newpath contains "/.") or
|
||||
(mkdir and evt.arg.path contains "/.") or
|
||||
(open_write and evt.arg.flags contains "O_CREAT" and fd.name contains "/." and not fd.name pmatch (exclude_hidden_directories)))
|
||||
)
|
||||
output: >
|
||||
Hidden file or directory created (user=%user.name command=%proc.cmdline
|
||||
file=%fd.name container_id=%container.id container_name=%container.name image=%container.image.repository:%container.image.tag)
|
||||
file=%fd.name newpath=%evt.arg.newpath container_id=%container.id container_name=%container.name image=%container.image.repository:%container.image.tag)
|
||||
priority:
|
||||
NOTICE
|
||||
tag: [file, mitre_persistence]
|
||||
@@ -2387,7 +2471,6 @@
|
||||
priority: NOTICE
|
||||
tags: [network, process, mitre_lateral_movement, mitre_exfiltration]
|
||||
|
||||
|
||||
- rule: Create Symlink Over Sensitive Files
|
||||
desc: Detect symlink created over sensitive files
|
||||
condition: >
|
||||
@@ -2397,6 +2480,103 @@
|
||||
Symlinks created over senstivie files (user=%user.name command=%proc.cmdline target=%evt.arg.target linkpath=%evt.arg.linkpath parent_process=%proc.pname)
|
||||
priority: NOTICE
|
||||
tags: [file, mitre_exfiltration]
|
||||
|
||||
- list: miner_ports
|
||||
items: [
|
||||
25, 3333, 3334, 3335, 3336, 3357, 4444,
|
||||
5555, 5556, 5588, 5730, 6099, 6666, 7777,
|
||||
7778, 8000, 8001, 8008, 8080, 8118, 8333,
|
||||
8888, 8899, 9332, 9999, 14433, 14444,
|
||||
45560, 45700
|
||||
]
|
||||
|
||||
- list: miner_domains
|
||||
items: [
|
||||
"asia1.ethpool.org","ca.minexmr.com",
|
||||
"cn.stratum.slushpool.com","de.minexmr.com",
|
||||
"eth-ar.dwarfpool.com","eth-asia.dwarfpool.com",
|
||||
"eth-asia1.nanopool.org","eth-au.dwarfpool.com",
|
||||
"eth-au1.nanopool.org","eth-br.dwarfpool.com",
|
||||
"eth-cn.dwarfpool.com","eth-cn2.dwarfpool.com",
|
||||
"eth-eu.dwarfpool.com","eth-eu1.nanopool.org",
|
||||
"eth-eu2.nanopool.org","eth-hk.dwarfpool.com",
|
||||
"eth-jp1.nanopool.org","eth-ru.dwarfpool.com",
|
||||
"eth-ru2.dwarfpool.com","eth-sg.dwarfpool.com",
|
||||
"eth-us-east1.nanopool.org","eth-us-west1.nanopool.org",
|
||||
"eth-us.dwarfpool.com","eth-us2.dwarfpool.com",
|
||||
"eu.stratum.slushpool.com","eu1.ethermine.org",
|
||||
"eu1.ethpool.org","fr.minexmr.com",
|
||||
"mine.moneropool.com","mine.xmrpool.net",
|
||||
"pool.minexmr.com","pool.monero.hashvault.pro",
|
||||
"pool.supportxmr.com","sg.minexmr.com",
|
||||
"sg.stratum.slushpool.com","stratum-eth.antpool.com",
|
||||
"stratum-ltc.antpool.com","stratum-zec.antpool.com",
|
||||
"stratum.antpool.com","us-east.stratum.slushpool.com",
|
||||
"us1.ethermine.org","us1.ethpool.org",
|
||||
"us2.ethermine.org","us2.ethpool.org",
|
||||
"xmr-asia1.nanopool.org","xmr-au1.nanopool.org",
|
||||
"xmr-eu1.nanopool.org","xmr-eu2.nanopool.org",
|
||||
"xmr-jp1.nanopool.org","xmr-us-east1.nanopool.org",
|
||||
"xmr-us-west1.nanopool.org","xmr.crypto-pool.fr",
|
||||
"xmr.pool.minergate.com"
|
||||
]
|
||||
|
||||
- list: https_miner_domains
|
||||
items: [
|
||||
"ca.minexmr.com",
|
||||
"cn.stratum.slushpool.com",
|
||||
"de.minexmr.com",
|
||||
"fr.minexmr.com",
|
||||
"mine.moneropool.com",
|
||||
"mine.xmrpool.net",
|
||||
"pool.minexmr.com",
|
||||
"sg.minexmr.com",
|
||||
"stratum-eth.antpool.com",
|
||||
"stratum-ltc.antpool.com",
|
||||
"stratum-zec.antpool.com",
|
||||
"stratum.antpool.com",
|
||||
"xmr.crypto-pool.fr"
|
||||
]
|
||||
|
||||
- list: http_miner_domains
|
||||
items: [
|
||||
"ca.minexmr.com",
|
||||
"de.minexmr.com",
|
||||
"fr.minexmr.com",
|
||||
"mine.moneropool.com",
|
||||
"mine.xmrpool.net",
|
||||
"pool.minexmr.com",
|
||||
"sg.minexmr.com",
|
||||
"xmr.crypto-pool.fr"
|
||||
]
|
||||
|
||||
# Add rule based on crypto mining IOCs
|
||||
- macro: minerpool_https
|
||||
condition: (fd.sport="443" and fd.sip.name in (https_miner_domains))
|
||||
|
||||
- macro: minerpool_http
|
||||
condition: (fd.sport="80" and fd.sip.name in (http_miner_domains))
|
||||
|
||||
- macro: minerpool_other
|
||||
condition: (fd.sport in (miner_ports) and fd.sip.name in (miner_domains))
|
||||
|
||||
- macro: net_miner_pool
|
||||
condition: (evt.type in (sendto, sendmsg) and evt.dir=< and ((minerpool_http) or (minerpool_https) or (minerpool_other)))
|
||||
|
||||
- rule: Detect outbound connections to common miner pool ports
|
||||
desc: Miners typically connect to miner pools on common ports.
|
||||
condition: net_miner_pool
|
||||
output: Outbound connection to IP/Port flagged by cryptoioc.ch (command=%proc.cmdline port=%fd.rport ip=%fd.rip container=%container.info image=%container.image.repository)
|
||||
priority: CRITICAL
|
||||
tags: [network, mitre_execution]
|
||||
|
||||
- rule: Detect crypto miners using the Stratum protocol
|
||||
desc: Miners typically specify the mining pool to connect to with a URI that begins with 'stratum+tcp'
|
||||
condition: spawned_process and proc.cmdline contains "stratum+tcp"
|
||||
output: Possible miner running (command=%proc.cmdline container=%container.info image=%container.image.repository)
|
||||
priority: CRITICAL
|
||||
tags: [process, mitre_execution]
|
||||
|
||||
# Application rules have moved to application_rules.yaml. Please look
|
||||
# there if you want to enable them by adding to
|
||||
# falco_rules.local.yaml.
|
||||
|
||||
@@ -18,6 +18,10 @@
|
||||
configure_file(debian/postinst.in debian/postinst)
|
||||
configure_file(debian/prerm.in debian/prerm)
|
||||
|
||||
if(NOT SYSDIG_DIR)
|
||||
get_filename_component(SYSDIG_DIR "${PROJECT_SOURCE_DIR}/../sysdig" REALPATH)
|
||||
endif()
|
||||
|
||||
file(COPY "${PROJECT_SOURCE_DIR}/scripts/debian/falco"
|
||||
DESTINATION "${PROJECT_BINARY_DIR}/scripts/debian")
|
||||
|
||||
|
||||
26
scripts/build
Executable file
26
scripts/build
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -xeuo pipefail
|
||||
|
||||
SOURCE_DIR=$1
|
||||
BUILD_DIR=$2
|
||||
FALCOBUILDER_IMAGE="falcosecurity/falco-builder"
|
||||
FALCOTESTER_IMAGE="falcosecurity/falco-tester"
|
||||
|
||||
docker run --user "$(id -u)":"$(id -g)" -v /etc/passwd:/etc/passwd:ro -e BUILD_TYPE="$BUILD_TYPE" -v "$SOURCE_DIR":/source -v "$BUILD_DIR":/build "$FALCOBUILDER_IMAGE" cmake
|
||||
docker run --user "$(id -u)":"$(id -g)" -v /etc/passwd:/etc/passwd:ro -e BUILD_TYPE="$BUILD_TYPE" -v "$SOURCE_DIR":/source -v "$BUILD_DIR":/build "$FALCOBUILDER_IMAGE" package
|
||||
docker run --user "$(id -u)":"$(id -g)" -v /etc/passwd:/etc/passwd:ro -e BUILD_TYPE="$BUILD_TYPE" -v "$SOURCE_DIR":/source -v "$BUILD_DIR":/build "$FALCOBUILDER_IMAGE" tests
|
||||
|
||||
# Deduct currently built version
|
||||
CURRENT_FALCO_VERSION=$(docker run -v "$BUILD_DIR":/build "$FALCOBUILDER_IMAGE" bash -c "./build/$BUILD_TYPE/userspace/falco/falco --version" | cut -d' ' -f3 | tr -d '\r')
|
||||
|
||||
# Execute regression tests
|
||||
docker run \
|
||||
-v /boot:/boot:ro \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v /etc/passwd:/etc/passwd:ro \
|
||||
-v "$SOURCE_DIR":/source \
|
||||
-v "$BUILD_DIR":/build \
|
||||
-e BUILD_TYPE="$BUILD_TYPE" \
|
||||
-e FALCO_VERSION="$CURRENT_FALCO_VERSION" \
|
||||
"$FALCOTESTER_IMAGE" test
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (C) 2016-2018 Draios Inc dba Sysdig.
|
||||
#
|
||||
@@ -21,17 +21,17 @@ set -ex
|
||||
|
||||
PREFIX=$1
|
||||
|
||||
if [ -z $PREFIX ]; then
|
||||
if [ -z "$PREFIX" ]; then
|
||||
PREFIX=.
|
||||
fi
|
||||
|
||||
mkdir -p $PREFIX
|
||||
|
||||
gcc -O2 -fPIC -I$LUA_INCLUDE -c lpcap.c -o $PREFIX/lpcap.o
|
||||
gcc -O2 -fPIC -I$LUA_INCLUDE -c lpcode.c -o $PREFIX/lpcode.o
|
||||
gcc -O2 -fPIC -I$LUA_INCLUDE -c lpprint.c -o $PREFIX/lpprint.o
|
||||
gcc -O2 -fPIC -I$LUA_INCLUDE -c lptree.c -o $PREFIX/lptree.o
|
||||
gcc -O2 -fPIC -I$LUA_INCLUDE -c lpvm.c -o $PREFIX/lpvm.o
|
||||
gcc -O2 -fPIC -I"$LUA_INCLUDE" -c lpcap.c -o $PREFIX/lpcap.o
|
||||
gcc -O2 -fPIC -I"$LUA_INCLUDE" -c lpcode.c -o $PREFIX/lpcode.o
|
||||
gcc -O2 -fPIC -I"$LUA_INCLUDE" -c lpprint.c -o $PREFIX/lpprint.o
|
||||
gcc -O2 -fPIC -I"$LUA_INCLUDE" -c lptree.c -o $PREFIX/lptree.o
|
||||
gcc -O2 -fPIC -I"$LUA_INCLUDE" -c lpvm.c -o $PREFIX/lpvm.o
|
||||
|
||||
|
||||
# For building lpeg.so, which we don't need now that we're statically linking lpeg.a into falco
|
||||
|
||||
@@ -1,3 +1 @@
|
||||
Sysdig Falco instruments your physical and virtual machines at the OS level by installing into the Linux kernel and capturing system calls and other OS events.
|
||||
Then, using a rule-based configuration, you can specify filters for events of interest that you would like to log or be notified of.
|
||||
|
||||
Falco is an open source project for intrusion and abnormality detection for Cloud Native platforms such as Kubernetes, Mesosphere, and Cloud Foundry. Detect abnormal application behavior. Alert via Slack, Fluentd, NATS, and more. Protect your platform by taking action through serverless (FaaS) frameworks, or other automation.
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (C) 2016-2018 Draios Inc dba Sysdig.
|
||||
#
|
||||
@@ -16,8 +17,6 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
cat ../sysdig/userspace/libscap/syscall_info_table.c | grep EF_DROP_FALCO | sed -e 's/.*\"\(.*\)\".*/\1/' | sort > ignored_syscall_info_table.txt
|
||||
cat ../sysdig/driver/event_table.c | grep EF_DROP_FALCO | sed -e 's/[^\"]*\"\([^\"]*\)\".*/\1/' | sort | uniq > ignored_driver_event_table.txt
|
||||
cat ../sysdig/userspace/libscap/event_table.c | grep EF_DROP_FALCO | sed -e 's/[^\"]*\"\([^\"]*\)\".*/\1/' | sort | uniq > ignored_userspace_event_table.txt
|
||||
|
||||
129
scripts/jenkins/build-pipeline/Jenkinsfile
vendored
129
scripts/jenkins/build-pipeline/Jenkinsfile
vendored
@@ -1,66 +1,95 @@
|
||||
void setBuildStatus(String context, String message, String state) {
|
||||
step([
|
||||
$class: "GitHubCommitStatusSetter",
|
||||
reposSource: [$class: "ManuallyEnteredRepositorySource", url: "https://github.com/falcosecurity/falco"],
|
||||
contextSource: [$class: "ManuallyEnteredCommitContextSource", context: context],
|
||||
errorHandlers: [[$class: "ChangingBuildStatusErrorHandler", result: "UNSTABLE"]],
|
||||
statusResultSource: [ $class: "ConditionalStatusResultSource", results: [[$class: "AnyBuildResult", message: message, state: state]] ]
|
||||
]);
|
||||
$class: "GitHubCommitStatusSetter",
|
||||
reposSource: [
|
||||
$class: "ManuallyEnteredRepositorySource",
|
||||
url: "https://github.com/falcosecurity/falco"
|
||||
],
|
||||
contextSource: [
|
||||
$class: "ManuallyEnteredCommitContextSource",
|
||||
context: context
|
||||
],
|
||||
errorHandlers: [[
|
||||
$class: "ChangingBuildStatusErrorHandler",
|
||||
result: "UNSTABLE"
|
||||
]],
|
||||
statusResultSource: [
|
||||
$class: "ConditionalStatusResultSource",
|
||||
results: [[
|
||||
$class: "AnyBuildResult",
|
||||
message: message,
|
||||
state: state
|
||||
]]
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
def version = 'UNKNOWN'
|
||||
|
||||
pipeline {
|
||||
agent { label "agent-docker-builder" }
|
||||
stages {
|
||||
stage("Check out dependencies") {
|
||||
steps {
|
||||
dir("falco") {
|
||||
checkout([$class: "GitSCM",
|
||||
branches: [[name: "refs/heads/"+env.BRANCH_NAME]],
|
||||
doGenerateSubmoduleConfigurations: false,
|
||||
extensions: [],
|
||||
submoduleCfg: [],
|
||||
userRemoteConfigs: [[credentialsId: "github-jenkins-user-token", url: "https://github.com/draios/falco"]]])
|
||||
}
|
||||
dir("sysdig") {
|
||||
checkout([$class: "GitSCM",
|
||||
branches: [[name: "dev"]],
|
||||
doGenerateSubmoduleConfigurations: false,
|
||||
extensions: [],
|
||||
submoduleCfg: [],
|
||||
userRemoteConfigs: [[credentialsId: "github-jenkins-user-token", url: "https://github.com/draios/sysdig"]]])
|
||||
steps {
|
||||
dir("falco") {
|
||||
checkout([
|
||||
$class: "GitSCM",
|
||||
branches: [[name: "refs/heads/"+env.BRANCH_NAME]],
|
||||
doGenerateSubmoduleConfigurations: false,
|
||||
extensions: [],
|
||||
submoduleCfg: [],
|
||||
userRemoteConfigs: [[
|
||||
credentialsId: "github-jenkins-user-token",
|
||||
url: "https://github.com/falcosecurity/falco"
|
||||
]]
|
||||
])
|
||||
}
|
||||
dir("sysdig") {
|
||||
checkout([
|
||||
$class: "GitSCM",
|
||||
branches: [[name: "dev"]],
|
||||
doGenerateSubmoduleConfigurations: false,
|
||||
extensions: [],
|
||||
submoduleCfg: [],
|
||||
userRemoteConfigs: [[
|
||||
credentialsId: "github-jenkins-user-token",
|
||||
url: "https://github.com/draios/sysdig"
|
||||
]]
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage("Build") {
|
||||
steps {
|
||||
script{
|
||||
sh("./falco/scripts/jenkins/build-pipeline/build.sh")
|
||||
}
|
||||
}
|
||||
post {
|
||||
success {
|
||||
setBuildStatus("Build", "Build Successful", "SUCCESS")
|
||||
}
|
||||
failure {
|
||||
setBuildStatus("Build", "Build Failed", "FAILURE")
|
||||
}
|
||||
}
|
||||
stage("Build") {
|
||||
steps {
|
||||
script{
|
||||
version = sh(returnStdout: true, script: "./falco/scripts/jenkins/build-pipeline/version")
|
||||
sh("./falco/scripts/jenkins/build-pipeline/build ${version}")
|
||||
}
|
||||
}
|
||||
post {
|
||||
success {
|
||||
setBuildStatus("Build", "Build Successful", "SUCCESS")
|
||||
}
|
||||
failure {
|
||||
setBuildStatus("Build", "Build Failed", "FAILURE")
|
||||
}
|
||||
}
|
||||
}
|
||||
stage("Run tests") {
|
||||
steps {
|
||||
script{
|
||||
sh("./falco/scripts/jenkins/build-pipeline/run-tests.sh")
|
||||
}
|
||||
steps {
|
||||
script{
|
||||
sh("./falco/scripts/jenkins/build-pipeline/run-tests ${version}")
|
||||
}
|
||||
}
|
||||
post {
|
||||
success {
|
||||
setBuildStatus("Run tests", "All tests passed", "SUCCESS")
|
||||
}
|
||||
failure {
|
||||
setBuildStatus("Run tests", "One or more tests failed", "FAILURE")
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
success {
|
||||
setBuildStatus("Run tests", "All tests passed", "SUCCESS")
|
||||
}
|
||||
failure {
|
||||
setBuildStatus("Run tests", "One or more tests failed", "FAILURE")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
|
||||
28
scripts/jenkins/build-pipeline/build
Executable file
28
scripts/jenkins/build-pipeline/build
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
>&2 echo "Missing arguments."
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$1" ]; then
|
||||
>&2 echo "Missing version."
|
||||
exit 1
|
||||
fi
|
||||
if [ "$1" == "UNKNOWN" ]; then
|
||||
>&2 echo "Unknown version."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
FALCO_VERSION=$1
|
||||
BUILD_DIR="${WORKSPACE}/build"
|
||||
FALCOBUILDER_IMAGE="falcosecurity/falco-builder"
|
||||
|
||||
docker pull $FALCOBUILDER_IMAGE
|
||||
|
||||
rm -rf "$BUILD_DIR"
|
||||
mkdir "$BUILD_DIR"
|
||||
|
||||
docker run -u "$(id -u):$(id -g)" -v /etc/passwd:/etc/passwd:ro -e FALCO_VERSION="$FALCO_VERSION" -v "$WORKSPACE":/source -v "$BUILD_DIR":/build "$FALCOBUILDER_IMAGE" cmake
|
||||
docker run -u "$(id -u):$(id -g)" -v /etc/passwd:/etc/passwd:ro -e FALCO_VERSION="$FALCO_VERSION" -v $"$WORKSPACE":/source -v "$BUILD_DIR":/build "$FALCOBUILDER_IMAGE" package
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -xeuo pipefail
|
||||
|
||||
export FALCO_VERSION=0.1.$((2700+BUILD_NUMBER))dev
|
||||
|
||||
rm -rf ${WORKSPACE}/build
|
||||
mkdir ${WORKSPACE}/build
|
||||
|
||||
docker run --user $(id -u):$(id -g) -v /etc/passwd:/etc/passwd:ro -e FALCO_VERSION=${FALCO_VERSION} -e MAKE_JOBS=4 -v ${WORKSPACE}:/source -v ${WORKSPACE}/build:/build falcosecurity/falco-builder cmake
|
||||
docker run --user $(id -u):$(id -g) -v /etc/passwd:/etc/passwd:ro -e FALCO_VERSION=${FALCO_VERSION} -e MAKE_JOBS=4 -v ${WORKSPACE}:/source -v ${WORKSPACE}/build:/build falcosecurity/falco-builder package
|
||||
33
scripts/jenkins/build-pipeline/run-tests
Executable file
33
scripts/jenkins/build-pipeline/run-tests
Executable file
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
>&2 echo "Missing arguments."
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$1" ]; then
|
||||
>&2 echo "Missing version."
|
||||
exit 1
|
||||
fi
|
||||
if [ "$1" == "UNKNOWN" ]; then
|
||||
>&2 echo "Unknown version."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
FALCO_VERSION=$1
|
||||
BUILD_DIR="${WORKSPACE}/build"
|
||||
FALCOTESTER_IMAGE="falcosecurity/falco-tester"
|
||||
|
||||
docker pull $FALCOTESTER_IMAGE
|
||||
|
||||
docker run \
|
||||
-v /boot:/boot:ro \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v /etc/passwd:/etc/passwd:ro \
|
||||
-e FALCO_VERSION="$FALCO_VERSION" \
|
||||
-v "$WORKSPACE":/source \
|
||||
-v "$BUILD_DIR":/build \
|
||||
"$FALCOTESTER_IMAGE" test
|
||||
|
||||
exit 0
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -xeuo pipefail
|
||||
|
||||
export FALCO_VERSION=0.1.$((2700+BUILD_NUMBER))dev
|
||||
|
||||
docker pull falcosecurity/falco-tester
|
||||
docker run -v /boot:/boot:ro -v /var/run/docker.sock:/var/run/docker.sock -v /etc/passwd:/etc/passwd:ro -e FALCO_VERSION=${FALCO_VERSION} -v ${WORKSPACE}:/source -v ${WORKSPACE}/build:/build falcosecurity/falco-tester
|
||||
|
||||
exit 0
|
||||
23
scripts/jenkins/build-pipeline/version
Executable file
23
scripts/jenkins/build-pipeline/version
Executable file
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Do not add "x"
|
||||
set -eu -o pipefail
|
||||
|
||||
BUILD_DIR="${WORKSPACE}/build"
|
||||
FALCOBUILDER_IMAGE="falcosecurity/falco-builder"
|
||||
|
||||
docker pull $FALCOBUILDER_IMAGE > /dev/null
|
||||
|
||||
rm -rf "$BUILD_DIR"
|
||||
mkdir "$BUILD_DIR"
|
||||
|
||||
CMAKE_CMD="docker run -u $(id -u):$(id -g) -v /etc/passwd:/etc/passwd:ro -v $WORKSPACE:/source -v $BUILD_DIR:/build -a stdout -a stderr $FALCOBUILDER_IMAGE cmake"
|
||||
|
||||
FALCO_VERSION=$($CMAKE_CMD | grep -oP "Falco version: v?\K(\d+)\.[a-z0-9]{1,7}(\.[a-z0-9]+)?" || echo "UNKNOWN")
|
||||
|
||||
if [ "$FALCO_VERSION" == "UNKNOWN" ]; then
|
||||
>&2 echo "Unknown version."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "$FALCO_VERSION.$((2700+BUILD_NUMBER))"
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (C) 2016-2018 Draios Inc dba Sysdig.
|
||||
#
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright (C) 2016-2018 Draios Inc dba Sysdig.
|
||||
#
|
||||
@@ -34,13 +34,19 @@ class FalcoTest(Test):
|
||||
"""
|
||||
Load the sysdig kernel module if not already loaded.
|
||||
"""
|
||||
build_type = "Release"
|
||||
build_type = "release"
|
||||
if 'BUILD_TYPE' in os.environ:
|
||||
build_type = os.environ['BUILD_TYPE']
|
||||
build_type = os.environ['BUILD_TYPE'].lower()
|
||||
build_type = "debug" if build_type == "debug" else "release"
|
||||
|
||||
build_dir = os.path.join('/build', build_type)
|
||||
if not os.path.exists(build_dir):
|
||||
build_dir = '../build'
|
||||
self.falcodir = self.params.get('falcodir', '/', default=os.path.join(self.basedir, build_dir))
|
||||
|
||||
self.stdout_is = self.params.get('stdout_is', '*', default='')
|
||||
self.stderr_is = self.params.get('stderr_is', '*', default='')
|
||||
|
||||
self.stdout_contains = self.params.get('stdout_contains', '*', default='')
|
||||
|
||||
if not isinstance(self.stdout_contains, list):
|
||||
@@ -83,8 +89,21 @@ class FalcoTest(Test):
|
||||
if not isinstance(self.rules_file, list):
|
||||
self.rules_file = [self.rules_file]
|
||||
|
||||
self.validate_rules_file = self.params.get('validate_rules_file', '*', default=False)
|
||||
|
||||
if self.validate_rules_file == False:
|
||||
self.validate_rules_file = []
|
||||
else:
|
||||
if not isinstance(self.validate_rules_file, list):
|
||||
self.validate_rules_file = [self.validate_rules_file]
|
||||
|
||||
self.rules_args = ""
|
||||
|
||||
for file in self.validate_rules_file:
|
||||
if not os.path.isabs(file):
|
||||
file = os.path.join(self.basedir, file)
|
||||
self.rules_args = self.rules_args + "-V " + file + " "
|
||||
|
||||
for file in self.rules_file:
|
||||
if not os.path.isabs(file):
|
||||
file = os.path.join(self.basedir, file)
|
||||
@@ -252,7 +271,7 @@ class FalcoTest(Test):
|
||||
triggered_rules = match.group(1)
|
||||
|
||||
for rule, count in self.detect_counts.iteritems():
|
||||
expected = '\s{}: (\d+)'.format(rule)
|
||||
expected = '\s{}: (\d+)'.format(re.sub(r'([$\.*+?()[\]{}|^])', r'\\\1', rule))
|
||||
match = re.search(expected, triggered_rules)
|
||||
|
||||
if match is None:
|
||||
@@ -433,6 +452,15 @@ class FalcoTest(Test):
|
||||
|
||||
res = self.falco_proc.run(timeout=180, sig=9)
|
||||
|
||||
if self.stdout_is != '':
|
||||
print(self.stdout_is)
|
||||
if self.stdout_is != res.stdout:
|
||||
self.fail("Stdout was not exactly {}".format(self.stdout_is))
|
||||
|
||||
if self.stderr_is != '':
|
||||
if self.stderr_is != res.stdout:
|
||||
self.fail("Stdout was not exactly {}".format(self.stderr_is))
|
||||
|
||||
for pattern in self.stderr_contains:
|
||||
match = re.search(pattern, res.stderr)
|
||||
if match is None:
|
||||
|
||||
@@ -86,6 +86,15 @@ trace_files: !mux
|
||||
- rules/rule_names_with_spaces.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_names_with_regex_chars:
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/rule_names_with_regex_chars.yaml
|
||||
detect_counts:
|
||||
- 'Open From Cat ($\.*+?()[]{}|^)': 8
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
multiple_rules_first_empty:
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
@@ -114,6 +123,18 @@ trace_files: !mux
|
||||
trace_file: trace_files/cat_write.scap
|
||||
all_events: True
|
||||
|
||||
multiple_docs:
|
||||
detect: True
|
||||
detect_level:
|
||||
- WARNING
|
||||
- INFO
|
||||
- ERROR
|
||||
rules_file:
|
||||
- rules/single_rule.yaml
|
||||
- rules/double_rule.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
all_events: True
|
||||
|
||||
rules_directory:
|
||||
detect: True
|
||||
detect_level:
|
||||
@@ -238,6 +259,341 @@ trace_files: !mux
|
||||
- rules/endswith.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_not_yaml:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Rules content is not yaml
|
||||
---
|
||||
This 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: |+
|
||||
Rules content is not yaml array of objects
|
||||
---
|
||||
foo: bar
|
||||
---
|
||||
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: |+
|
||||
Unexpected element of type string. Each element should be a yaml associative array.
|
||||
---
|
||||
- foo
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_array_item_not_object.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_unexpected object:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Unknown rule object: {foo="bar"}
|
||||
---
|
||||
- foo: bar
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_unexpected_object.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_engine_version_not_number:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Value of required_engine_version must be a number
|
||||
---
|
||||
- required_engine_version: not-a-number
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_engine_version_not_number.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_yaml_parse_error:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
mapping values are not allowed in this context
|
||||
---
|
||||
this : is : not : yaml
|
||||
---
|
||||
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: |+
|
||||
List must have property items
|
||||
---
|
||||
- list: bad_list
|
||||
no_items: foo
|
||||
---
|
||||
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: |+
|
||||
Macro must have property condition
|
||||
---
|
||||
- macro: bad_macro
|
||||
nope: 1
|
||||
---
|
||||
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: |+
|
||||
Rule must have property output
|
||||
---
|
||||
- rule: no output rule
|
||||
desc: some desc
|
||||
condition: evt.type=fork
|
||||
priority: INFO
|
||||
---
|
||||
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: |+
|
||||
Rule must have property condition
|
||||
---
|
||||
- rule: no condition rule
|
||||
append: true
|
||||
---
|
||||
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: |+
|
||||
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_rules_file:
|
||||
- rules/invalid_append_macro_dangling.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_list_append_dangling:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
List my_list has 'append' key but no list by that name already exists
|
||||
---
|
||||
- list: my_list
|
||||
items: [not-cat]
|
||||
append: true
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/list_append_failure.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_rule_append_dangling:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Rule my_rule has 'append' key but no rule by that name already exists
|
||||
---
|
||||
- rule: my_rule
|
||||
condition: evt.type=open
|
||||
append: true
|
||||
---
|
||||
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: Compilation error when compiling "foo": Undefined macro 'foo' used in filter.
|
||||
---
|
||||
- macro: some macro
|
||||
condition: foo
|
||||
append: false
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_base_macro.yaml
|
||||
- rules/invalid_overwrite_macro.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_append_macro:
|
||||
exit_status: 1
|
||||
stdout_contains: |+
|
||||
.*invalid_base_macro.yaml: Ok
|
||||
.*invalid_append_macro.yaml: Compilation error when compiling "evt.type=execve foo": 17: syntax error, unexpected 'foo', expecting 'or', 'and'
|
||||
---
|
||||
- macro: some macro
|
||||
condition: evt.type=execve
|
||||
|
||||
- macro: some macro
|
||||
condition: foo
|
||||
append: true
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_base_macro.yaml
|
||||
- rules/invalid_append_macro.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_overwrite_macro_multiple_docs:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Compilation error when compiling "foo": Undefined macro 'foo' used in filter.
|
||||
---
|
||||
- macro: some macro
|
||||
condition: foo
|
||||
append: false
|
||||
---
|
||||
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: |+
|
||||
Compilation error when compiling "evt.type=execve foo": 17: syntax error, unexpected 'foo', expecting 'or', 'and'
|
||||
---
|
||||
- macro: some macro
|
||||
condition: evt.type=execve
|
||||
|
||||
- macro: some macro
|
||||
condition: foo
|
||||
append: true
|
||||
---
|
||||
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: Undefined macro 'bar' used in filter.
|
||||
---
|
||||
- rule: some rule
|
||||
desc: some desc
|
||||
condition: bar
|
||||
output: some output
|
||||
priority: INFO
|
||||
append: false
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_base_rule.yaml
|
||||
- rules/invalid_overwrite_rule.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_append_rule:
|
||||
exit_status: 1
|
||||
stdout_contains: |+
|
||||
.*invalid_base_rule.yaml: Ok
|
||||
.*invalid_append_rule.yaml: Compilation error when compiling "evt.type=open bar": 15: syntax error, unexpected 'bar', 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_rules_file:
|
||||
- rules/invalid_base_rule.yaml
|
||||
- rules/invalid_append_rule.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_overwrite_rule_multiple_docs:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Undefined macro 'bar' used in filter.
|
||||
---
|
||||
- rule: some rule
|
||||
desc: some desc
|
||||
condition: bar
|
||||
output: some output
|
||||
priority: INFO
|
||||
append: false
|
||||
---
|
||||
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: syntax error, unexpected 'bar', 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_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: |+
|
||||
Rule name is empty
|
||||
---
|
||||
- rule:
|
||||
desc: some desc
|
||||
condition: evt.type=execve
|
||||
output: some output
|
||||
---
|
||||
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: |+
|
||||
List name is empty
|
||||
---
|
||||
- list:
|
||||
items: [foo]
|
||||
---
|
||||
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: |+
|
||||
Macro name is empty
|
||||
---
|
||||
- macro:
|
||||
condition: evt.type=execve
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_missing_macro_name.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_rule_output:
|
||||
exit_status: 1
|
||||
stderr_contains: "Runtime error: Error loading rules:.* Invalid output format 'An open was seen %not_a_real_field': 'invalid formatting token not_a_real_field'. Exiting."
|
||||
@@ -254,13 +610,13 @@ trace_files: !mux
|
||||
- open_from_cat
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
disabled_rules_using_regex:
|
||||
disabled_rules_using_substring:
|
||||
detect: False
|
||||
rules_file:
|
||||
- rules/empty_rules.yaml
|
||||
- rules/single_rule.yaml
|
||||
disabled_rules:
|
||||
- "open.*"
|
||||
- "open_from"
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
disabled_rules_using_enabled_flag:
|
||||
@@ -601,7 +957,7 @@ trace_files: !mux
|
||||
|
||||
list_append_failure:
|
||||
exit_status: 1
|
||||
stderr_contains: "List my_list has 'append' key but no list by that name already exists. Exiting"
|
||||
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
|
||||
@@ -621,7 +977,7 @@ trace_files: !mux
|
||||
|
||||
macro_append_failure:
|
||||
exit_status: 1
|
||||
stderr_contains: "Macro my_macro has 'append' key but no macro by that name already exists. Exiting"
|
||||
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
|
||||
@@ -641,7 +997,7 @@ trace_files: !mux
|
||||
|
||||
rule_append_failure:
|
||||
exit_status: 1
|
||||
stderr_contains: "Rule my_rule has 'append' key but no rule by that name already exists. Exiting"
|
||||
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
|
||||
|
||||
3
test/rules/invalid_append_macro.yaml
Normal file
3
test/rules/invalid_append_macro.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
- macro: some macro
|
||||
condition: foo
|
||||
append: true
|
||||
3
test/rules/invalid_append_macro_dangling.yaml
Normal file
3
test/rules/invalid_append_macro_dangling.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
- macro: dangling append
|
||||
condition: and evt.type=execve
|
||||
append: true
|
||||
8
test/rules/invalid_append_macro_multiple_docs.yaml
Normal file
8
test/rules/invalid_append_macro_multiple_docs.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
- macro: some macro
|
||||
condition: evt.type=execve
|
||||
---
|
||||
- macro: some macro
|
||||
condition: foo
|
||||
append: true
|
||||
|
||||
6
test/rules/invalid_append_rule.yaml
Normal file
6
test/rules/invalid_append_rule.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
- rule: some rule
|
||||
desc: some desc
|
||||
condition: bar
|
||||
output: some output
|
||||
priority: INFO
|
||||
append: true
|
||||
13
test/rules/invalid_append_rule_multiple_docs.yaml
Normal file
13
test/rules/invalid_append_rule_multiple_docs.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
- 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
|
||||
2
test/rules/invalid_append_rule_without_condition.yaml
Normal file
2
test/rules/invalid_append_rule_without_condition.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
- rule: no condition rule
|
||||
append: true
|
||||
1
test/rules/invalid_array_item_not_object.yaml
Normal file
1
test/rules/invalid_array_item_not_object.yaml
Normal file
@@ -0,0 +1 @@
|
||||
- foo
|
||||
2
test/rules/invalid_base_macro.yaml
Normal file
2
test/rules/invalid_base_macro.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
- macro: some macro
|
||||
condition: evt.type=execve
|
||||
5
test/rules/invalid_base_rule.yaml
Normal file
5
test/rules/invalid_base_rule.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
- rule: some rule
|
||||
desc: some desc
|
||||
condition: evt.type=open
|
||||
output: some output
|
||||
priority: INFO
|
||||
5
test/rules/invalid_condition_not_rule.yaml
Normal file
5
test/rules/invalid_condition_not_rule.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
- rule: condition not rule
|
||||
condition:
|
||||
desc: some desc
|
||||
output: some output
|
||||
priority: INFO
|
||||
34
test/rules/invalid_engine_version_not_number.yaml
Normal file
34
test/rules/invalid_engine_version_not_number.yaml
Normal file
@@ -0,0 +1,34 @@
|
||||
#
|
||||
# Copyright (C) 2016-2018 Draios Inc dba Sysdig.
|
||||
#
|
||||
# This file is part of falco.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
- required_engine_version: not-a-number
|
||||
|
||||
- list: cat_binaries
|
||||
items: [cat]
|
||||
|
||||
- list: cat_capable_binaries
|
||||
items: [cat_binaries]
|
||||
|
||||
- macro: is_cat
|
||||
condition: proc.name in (cat_capable_binaries)
|
||||
|
||||
- rule: open_from_cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and is_cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
priority: WARNING
|
||||
5
test/rules/invalid_list_without_items.yaml
Normal file
5
test/rules/invalid_list_without_items.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
- list: good_list
|
||||
items: [foo]
|
||||
|
||||
- list: bad_list
|
||||
no_items: foo
|
||||
2
test/rules/invalid_macro_comple_error.yaml
Normal file
2
test/rules/invalid_macro_comple_error.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
- macro: macro with comp error
|
||||
condition: gak
|
||||
6
test/rules/invalid_macro_without_condition.yaml
Normal file
6
test/rules/invalid_macro_without_condition.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
- macro: bad_macro
|
||||
nope: 1
|
||||
|
||||
- macro: good_macro
|
||||
condition: evt.type=execve
|
||||
|
||||
2
test/rules/invalid_missing_list_name.yaml
Normal file
2
test/rules/invalid_missing_list_name.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
- list:
|
||||
items: [foo]
|
||||
2
test/rules/invalid_missing_macro_name.yaml
Normal file
2
test/rules/invalid_missing_macro_name.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
- macro:
|
||||
condition: evt.type=execve
|
||||
4
test/rules/invalid_missing_rule_name.yaml
Normal file
4
test/rules/invalid_missing_rule_name.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
- rule:
|
||||
desc: some desc
|
||||
condition: evt.type=execve
|
||||
output: some output
|
||||
1
test/rules/invalid_not_array.yaml
Normal file
1
test/rules/invalid_not_array.yaml
Normal file
@@ -0,0 +1 @@
|
||||
foo: bar
|
||||
1
test/rules/invalid_not_yaml.yaml
Normal file
1
test/rules/invalid_not_yaml.yaml
Normal file
@@ -0,0 +1 @@
|
||||
This is not yaml
|
||||
3
test/rules/invalid_overwrite_macro.yaml
Normal file
3
test/rules/invalid_overwrite_macro.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
- macro: some macro
|
||||
condition: foo
|
||||
append: false
|
||||
8
test/rules/invalid_overwrite_macro_multiple_docs.yaml
Normal file
8
test/rules/invalid_overwrite_macro_multiple_docs.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
- macro: some macro
|
||||
condition: evt.type=execve
|
||||
---
|
||||
- macro: some macro
|
||||
condition: foo
|
||||
append: false
|
||||
|
||||
6
test/rules/invalid_overwrite_rule.yaml
Normal file
6
test/rules/invalid_overwrite_rule.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
- rule: some rule
|
||||
desc: some desc
|
||||
condition: bar
|
||||
output: some output
|
||||
priority: INFO
|
||||
append: false
|
||||
13
test/rules/invalid_overwrite_rule_multiple_docs.yaml
Normal file
13
test/rules/invalid_overwrite_rule_multiple_docs.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
- 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: false
|
||||
4
test/rules/invalid_rule_without_output.yaml
Normal file
4
test/rules/invalid_rule_without_output.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
- rule: no output rule
|
||||
desc: some desc
|
||||
condition: evt.type=fork
|
||||
priority: INFO
|
||||
1
test/rules/invalid_unexpected_object.yaml
Normal file
1
test/rules/invalid_unexpected_object.yaml
Normal file
@@ -0,0 +1 @@
|
||||
- foo: bar
|
||||
1
test/rules/invalid_yaml_parse_error.yaml
Normal file
1
test/rules/invalid_yaml_parse_error.yaml
Normal file
@@ -0,0 +1 @@
|
||||
this : is : not : yaml
|
||||
66
test/rules/multiple_docs.yaml
Normal file
66
test/rules/multiple_docs.yaml
Normal file
@@ -0,0 +1,66 @@
|
||||
---
|
||||
#
|
||||
# Copyright (C) 2016-2018 Draios Inc dba Sysdig.
|
||||
#
|
||||
# This file is part of falco.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
- required_engine_version: 2
|
||||
|
||||
- list: cat_binaries
|
||||
items: [cat]
|
||||
|
||||
- list: cat_capable_binaries
|
||||
items: [cat_binaries]
|
||||
|
||||
- macro: is_cat
|
||||
condition: proc.name in (cat_capable_binaries)
|
||||
|
||||
- rule: open_from_cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and is_cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
priority: WARNING
|
||||
---
|
||||
#
|
||||
# Copyright (C) 2016-2018 Draios Inc dba Sysdig.
|
||||
#
|
||||
# This file is part of falco.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# This ruleset depends on the is_cat macro defined in single_rule.yaml
|
||||
|
||||
- rule: exec_from_cat
|
||||
desc: A process named cat does execve
|
||||
condition: evt.type=execve and is_cat
|
||||
output: "An exec was seen (command=%proc.cmdline)"
|
||||
priority: ERROR
|
||||
|
||||
- rule: access_from_cat
|
||||
desc: A process named cat does an access
|
||||
condition: evt.type=access and is_cat
|
||||
output: "An access was seen (command=%proc.cmdline)"
|
||||
priority: INFO
|
||||
25
test/rules/rule_names_with_regex_chars.yaml
Normal file
25
test/rules/rule_names_with_regex_chars.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
#
|
||||
# Copyright (C) 2016-2018 Draios Inc dba Sysdig.
|
||||
#
|
||||
# This file is part of falco.
|
||||
#
|
||||
# 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: is_cat
|
||||
condition: proc.name=cat
|
||||
|
||||
- rule: Open From Cat ($\.*+?()[]{}|^)
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and is_cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
priority: WARNING
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (C) 2016-2018 Draios Inc dba Sysdig.
|
||||
#
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (C) 2016-2018 Draios Inc dba Sysdig.
|
||||
#
|
||||
|
||||
Binary file not shown.
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (C) 2016-2018 Draios Inc dba Sysdig.
|
||||
#
|
||||
@@ -23,4 +23,4 @@
|
||||
|
||||
# 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' $@
|
||||
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' "$@"
|
||||
|
||||
52
tests/CMakeLists.txt
Normal file
52
tests/CMakeLists.txt
Normal file
@@ -0,0 +1,52 @@
|
||||
#
|
||||
# Copyright (C) 2016-2019 Draios Inc dba Sysdig.
|
||||
#
|
||||
# This file is part of falco .
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy of
|
||||
# the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations under
|
||||
# the License.
|
||||
#
|
||||
set(FALCO_TESTS_SOURCES test_base.cpp engine/test_token_bucket.cpp falco/test_webserver.cpp)
|
||||
|
||||
set(FALCO_TESTED_LIBRARIES falco_engine)
|
||||
|
||||
option(FALCO_BUILD_TESTS "Determines whether to build tests." ON)
|
||||
|
||||
if(FALCO_BUILD_TESTS)
|
||||
enable_testing()
|
||||
if(NOT TARGET catch)
|
||||
include(DownloadCatch)
|
||||
endif()
|
||||
|
||||
if(NOT TARGET fakeit)
|
||||
include(DownloadFakeIt)
|
||||
endif()
|
||||
|
||||
add_executable(falco_test ${FALCO_TESTS_SOURCES})
|
||||
|
||||
target_link_libraries(falco_test PUBLIC ${FALCO_TESTED_LIBRARIES})
|
||||
target_include_directories(
|
||||
falco_test
|
||||
PUBLIC "${CATCH2_INCLUDE}"
|
||||
"${FAKEIT_INCLUDE}"
|
||||
"${PROJECT_SOURCE_DIR}/userspace/engine"
|
||||
"${YAMLCPP_INCLUDE_DIR}"
|
||||
"${CIVETWEB_INCLUDE_DIR}"
|
||||
"${PROJECT_SOURCE_DIR}/userspace/falco")
|
||||
|
||||
include(CMakeParseArguments)
|
||||
include(CTest)
|
||||
include(Catch)
|
||||
catch_discover_tests(falco_test)
|
||||
|
||||
add_custom_target(tests COMMAND ${CMAKE_CTEST_COMMAND} DEPENDS falco_test)
|
||||
endif()
|
||||
83
tests/engine/test_token_bucket.cpp
Normal file
83
tests/engine/test_token_bucket.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
Copyright (C) 2016-2019 Draios Inc dba Sysdig.
|
||||
|
||||
This file is part of falco.
|
||||
|
||||
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 "token_bucket.h"
|
||||
#include <catch.hpp>
|
||||
|
||||
using namespace Catch::literals;
|
||||
|
||||
TEST_CASE("token bucket default ctor", "[token_bucket]")
|
||||
{
|
||||
auto tb = new token_bucket();
|
||||
|
||||
REQUIRE(tb->get_tokens() == 1);
|
||||
|
||||
SECTION("initialising with specific time, rate 2 tokens/sec")
|
||||
{
|
||||
auto max = 2.0;
|
||||
uint64_t now = 1;
|
||||
tb->init(1.0, max, now);
|
||||
REQUIRE(tb->get_last_seen() == now);
|
||||
REQUIRE(tb->get_tokens() == max);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("token bucket ctor with custom timer", "[token_bucket]")
|
||||
{
|
||||
auto t = []() -> uint64_t { return 22; };
|
||||
auto tb = new token_bucket(t);
|
||||
|
||||
REQUIRE(tb->get_tokens() == 1);
|
||||
REQUIRE(tb->get_last_seen() == 22);
|
||||
}
|
||||
|
||||
TEST_CASE("token bucket with 2 tokens/sec rate, max 10 tokens", "[token_bucket]")
|
||||
{
|
||||
auto tb = new token_bucket();
|
||||
tb->init(2.0, 10, 1);
|
||||
|
||||
SECTION("claiming 5 tokens")
|
||||
{
|
||||
bool claimed = tb->claim(5, 1000000001);
|
||||
REQUIRE(tb->get_last_seen() == 1000000001);
|
||||
REQUIRE(tb->get_tokens() == 5.0_a);
|
||||
REQUIRE(claimed);
|
||||
|
||||
SECTION("claiming all the 7 remaining tokens")
|
||||
{
|
||||
bool claimed = tb->claim(7, 2000000001);
|
||||
REQUIRE(tb->get_last_seen() == 2000000001);
|
||||
REQUIRE(tb->get_tokens() == 0.0_a);
|
||||
REQUIRE(claimed);
|
||||
|
||||
SECTION("claiming 1 token more than the 2 available fails")
|
||||
{
|
||||
bool claimed = tb->claim(3, 3000000001);
|
||||
REQUIRE(tb->get_last_seen() == 3000000001);
|
||||
REQUIRE(tb->get_tokens() == 2.0_a);
|
||||
REQUIRE_FALSE(claimed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("token bucket default initialization", "[token_bucket]")
|
||||
{
|
||||
token_bucket tb;
|
||||
REQUIRE(tb.get_tokens() == 1);
|
||||
}
|
||||
31
tests/falco/test_webserver.cpp
Normal file
31
tests/falco/test_webserver.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
Copyright (C) 2016-2019 Draios Inc dba Sysdig.
|
||||
|
||||
This file is part of falco.
|
||||
|
||||
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 "webserver.h"
|
||||
#include <catch.hpp>
|
||||
|
||||
TEST_CASE("webserver must accept invalid data", "[!hide][webserver][k8s_audit_handler][accept_data]")
|
||||
{
|
||||
// falco_engine* engine = new falco_engine();
|
||||
// falco_outputs* outputs = new falco_outputs(engine);
|
||||
// std::string errstr;
|
||||
// std::string input("{\"kind\": 0}");
|
||||
//k8s_audit_handler::accept_data(engine, outputs, input, errstr);
|
||||
|
||||
REQUIRE(1 == 1);
|
||||
}
|
||||
24
tests/test_base.cpp
Normal file
24
tests/test_base.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
Copyright (C) 2016-2019 Draios Inc dba Sysdig.
|
||||
|
||||
This file is part of falco.
|
||||
|
||||
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.
|
||||
*/
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#define CATCH_CONFIG_CONSOLE_WIDTH 300
|
||||
#include <catch.hpp>
|
||||
|
||||
TEST_CASE("all test cases reside in other .cpp files (empty)", "[multi-file:1]")
|
||||
{
|
||||
}
|
||||
@@ -14,17 +14,12 @@
|
||||
# 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_directories("${PROJECT_SOURCE_DIR}/../sysdig/userspace/libsinsp/third-party/jsoncpp")
|
||||
include_directories("${PROJECT_SOURCE_DIR}/../sysdig/userspace/libscap")
|
||||
include_directories("${PROJECT_SOURCE_DIR}/../sysdig/userspace/libsinsp")
|
||||
include_directories("${PROJECT_BINARY_DIR}/userspace/engine")
|
||||
include_directories("${LUAJIT_INCLUDE}")
|
||||
include_directories("${NJSON_INCLUDE}")
|
||||
include_directories("${CURL_INCLUDE_DIR}")
|
||||
include_directories("${TBB_INCLUDE_DIR}")
|
||||
|
||||
add_library(falco_engine STATIC
|
||||
if(NOT SYSDIG_DIR)
|
||||
get_filename_component(SYSDIG_DIR "${PROJECT_SOURCE_DIR}/../sysdig" REALPATH)
|
||||
endif()
|
||||
|
||||
set(FALCO_ENGINE_SOURCE_FILES
|
||||
rules.cpp
|
||||
falco_common.cpp
|
||||
falco_engine.cpp
|
||||
@@ -33,10 +28,18 @@ add_library(falco_engine STATIC
|
||||
token_bucket.cpp
|
||||
formats.cpp)
|
||||
|
||||
add_library(falco_engine STATIC ${FALCO_ENGINE_SOURCE_FILES})
|
||||
|
||||
target_include_directories(falco_engine PUBLIC
|
||||
"${LUAJIT_INCLUDE}"
|
||||
"${NJSON_INCLUDE}"
|
||||
"${PROJECT_BINARY_DIR}/userspace/engine")
|
||||
"${CURL_INCLUDE_DIR}"
|
||||
"${TBB_INCLUDE_DIR}"
|
||||
"${SYSDIG_DIR}/userspace/libsinsp/third-party/jsoncpp"
|
||||
"${SYSDIG_DIR}/userspace/libscap"
|
||||
"${SYSDIG_DIR}/userspace/libsinsp"
|
||||
"${PROJECT_BINARY_DIR}/userspace/engine"
|
||||
)
|
||||
|
||||
target_link_libraries(falco_engine
|
||||
"${FALCO_SINSP_LIBRARY}"
|
||||
|
||||
@@ -93,21 +93,21 @@ void falco_engine::list_fields(bool names_only)
|
||||
if(!names_only)
|
||||
{
|
||||
printf("\n----------------------\n");
|
||||
printf("Field Class: %s (%s)\n\n", chk_field.name.c_str(), chk_field.desc.c_str());
|
||||
printf("Field Class: %s (%s)\n\n", chk_field.m_name.c_str(), chk_field.m_desc.c_str());
|
||||
}
|
||||
|
||||
for(auto &field : chk_field.fields)
|
||||
for(auto &field : chk_field.m_fields)
|
||||
{
|
||||
uint32_t l, m;
|
||||
|
||||
printf("%s", field.name.c_str());
|
||||
printf("%s", field.m_name.c_str());
|
||||
|
||||
if(names_only)
|
||||
{
|
||||
printf("\n");
|
||||
continue;
|
||||
}
|
||||
uint32_t namelen = field.name.size();
|
||||
uint32_t namelen = field.m_name.size();
|
||||
|
||||
if(namelen >= DESCRIPTION_TEXT_START)
|
||||
{
|
||||
@@ -120,7 +120,7 @@ void falco_engine::list_fields(bool names_only)
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
size_t desclen = field.desc.size();
|
||||
size_t desclen = field.m_desc.size();
|
||||
|
||||
for(l = 0; l < desclen; l++)
|
||||
{
|
||||
@@ -134,7 +134,7 @@ void falco_engine::list_fields(bool names_only)
|
||||
}
|
||||
}
|
||||
|
||||
printf("%c", field.desc.at(l));
|
||||
printf("%c", field.m_desc.at(l));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
@@ -206,17 +206,17 @@ void falco_engine::load_rules_file(const string &rules_filename, bool verbose, b
|
||||
load_rules(rules_content, verbose, all_events, required_engine_version);
|
||||
}
|
||||
|
||||
void falco_engine::enable_rule(const string &pattern, bool enabled, const string &ruleset)
|
||||
void falco_engine::enable_rule(const string &substring, bool enabled, const string &ruleset)
|
||||
{
|
||||
uint16_t ruleset_id = find_ruleset_id(ruleset);
|
||||
|
||||
m_sinsp_rules->enable(pattern, enabled, ruleset_id);
|
||||
m_k8s_audit_rules->enable(pattern, enabled, ruleset_id);
|
||||
m_sinsp_rules->enable(substring, enabled, ruleset_id);
|
||||
m_k8s_audit_rules->enable(substring, enabled, ruleset_id);
|
||||
}
|
||||
|
||||
void falco_engine::enable_rule(const string &pattern, bool enabled)
|
||||
void falco_engine::enable_rule(const string &substring, bool enabled)
|
||||
{
|
||||
enable_rule(pattern, enabled, m_default_ruleset);
|
||||
enable_rule(substring, enabled, m_default_ruleset);
|
||||
}
|
||||
|
||||
void falco_engine::enable_rule_by_tag(const set<string> &tags, bool enabled, const string &ruleset)
|
||||
@@ -365,46 +365,54 @@ unique_ptr<falco_engine::rule_result> falco_engine::process_k8s_audit_event(json
|
||||
|
||||
bool falco_engine::parse_k8s_audit_json(nlohmann::json &j, std::list<json_event> &evts)
|
||||
{
|
||||
// If the Kind is EventList, split it into individual events.
|
||||
if(j.value("kind", "<NA>") == "EventList")
|
||||
// Note that nlohmann::basic_json::value can throw nlohmann::basic_json::type_error (302, 306)
|
||||
try
|
||||
{
|
||||
for(auto &je : j["items"])
|
||||
// If the kind is EventList, split it into individual events
|
||||
if(j.value("kind", "<NA>") == "EventList")
|
||||
{
|
||||
for(auto &je : j["items"])
|
||||
{
|
||||
evts.emplace_back();
|
||||
je["kind"] = "Event";
|
||||
|
||||
uint64_t ns = 0;
|
||||
if(!sinsp_utils::parse_iso_8601_utc_string(je.value(k8s_audit_time, "<NA>"), ns))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string tmp;
|
||||
sinsp_utils::ts_to_string(ns, &tmp, false, true);
|
||||
|
||||
evts.back().set_jevt(je, ns);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if(j.value("kind", "<NA>") == "Event")
|
||||
{
|
||||
evts.emplace_back();
|
||||
je["kind"] = "Event";
|
||||
|
||||
uint64_t ns = 0;
|
||||
if(!sinsp_utils::parse_iso_8601_utc_string(je.value(k8s_audit_time, "<NA>"), ns))
|
||||
if(!sinsp_utils::parse_iso_8601_utc_string(j.value(k8s_audit_time, "<NA>"), ns))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string tmp;
|
||||
sinsp_utils::ts_to_string(ns, &tmp, false, true);
|
||||
|
||||
evts.back().set_jevt(je, ns);
|
||||
evts.back().set_jevt(j, ns);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if(j.value("kind", "<NA>") == "Event")
|
||||
{
|
||||
evts.emplace_back();
|
||||
uint64_t ns = 0;
|
||||
if(!sinsp_utils::parse_iso_8601_utc_string(j.value(k8s_audit_time, "<NA>"), ns))
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
evts.back().set_jevt(j, ns);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
catch(exception &e)
|
||||
{
|
||||
// Propagate the exception
|
||||
rethrow_exception(current_exception());
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
unique_ptr<falco_engine::rule_result> falco_engine::process_k8s_audit_event(json_event *ev)
|
||||
|
||||
@@ -76,16 +76,17 @@ public:
|
||||
void load_rules(const std::string &rules_content, bool verbose, bool all_events, uint64_t &required_engine_version);
|
||||
|
||||
//
|
||||
// Enable/Disable any rules matching the provided pattern
|
||||
// (regex). When provided, enable/disable these rules in the
|
||||
// Enable/Disable any rules matching the provided substring.
|
||||
// If the substring is "", all rules are enabled/disabled.
|
||||
// When provided, enable/disable these rules in the
|
||||
// context of the provided ruleset. The ruleset (id) can later
|
||||
// be passed as an argument to process_event(). This allows
|
||||
// for different sets of rules being active at once.
|
||||
//
|
||||
void enable_rule(const std::string &pattern, bool enabled, const std::string &ruleset);
|
||||
void enable_rule(const std::string &substring, bool enabled, const std::string &ruleset);
|
||||
|
||||
// Wrapper that assumes the default ruleset
|
||||
void enable_rule(const std::string &pattern, bool enabled);
|
||||
void enable_rule(const std::string &substring, bool enabled);
|
||||
|
||||
//
|
||||
// Enable/Disable any rules with any of the provided tags (set, exact matches only)
|
||||
|
||||
@@ -19,9 +19,9 @@ limitations under the License.
|
||||
|
||||
// The version of rules/filter fields/etc supported by this falco
|
||||
// engine.
|
||||
#define FALCO_ENGINE_VERSION (3)
|
||||
#define FALCO_ENGINE_VERSION (4)
|
||||
|
||||
// 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 "fb82780f268b91fb888876e6ac1142b5acca08e05b3a82c4b1b524ca88fa83d9"
|
||||
#define FALCO_FIELDS_CHECKSUM "ceb069d9f9b2d4ebcc5de39bddc53b7af2e6b8f072edc293668fd6ac4e532413"
|
||||
|
||||
@@ -19,8 +19,8 @@ limitations under the License.
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "uri.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "falco_common.h"
|
||||
#include "json_evt.h"
|
||||
@@ -30,7 +30,6 @@ using namespace std;
|
||||
|
||||
json_event::json_event()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
json_event::~json_event()
|
||||
@@ -60,7 +59,7 @@ std::string json_event_filter_check::def_format(const json &j, std::string &fiel
|
||||
|
||||
std::string json_event_filter_check::json_as_string(const json &j)
|
||||
{
|
||||
if (j.type() == json::value_t::string)
|
||||
if(j.type() == json::value_t::string)
|
||||
{
|
||||
return j;
|
||||
}
|
||||
@@ -70,30 +69,55 @@ std::string json_event_filter_check::json_as_string(const json &j)
|
||||
}
|
||||
}
|
||||
|
||||
json_event_filter_check::field_info::field_info():
|
||||
m_idx_mode(IDX_NONE), m_idx_type(IDX_NUMERIC)
|
||||
{
|
||||
}
|
||||
|
||||
json_event_filter_check::field_info::field_info(std::string name,
|
||||
std::string desc):
|
||||
m_name(name),
|
||||
m_desc(desc),
|
||||
m_idx_mode(IDX_NONE), m_idx_type(IDX_NUMERIC)
|
||||
{
|
||||
}
|
||||
|
||||
json_event_filter_check::field_info::field_info(std::string name,
|
||||
std::string desc,
|
||||
index_mode mode):
|
||||
m_name(name),
|
||||
m_desc(desc),
|
||||
m_idx_mode(mode), m_idx_type(IDX_NUMERIC)
|
||||
{
|
||||
}
|
||||
|
||||
json_event_filter_check::field_info::field_info(std::string name,
|
||||
std::string desc,
|
||||
index_mode mode,
|
||||
index_type itype):
|
||||
m_name(name),
|
||||
m_desc(desc),
|
||||
m_idx_mode(mode), m_idx_type(itype)
|
||||
{
|
||||
}
|
||||
|
||||
json_event_filter_check::field_info::~field_info()
|
||||
{
|
||||
}
|
||||
|
||||
json_event_filter_check::alias::alias()
|
||||
: m_idx_mode(IDX_NONE), m_idx_type(IDX_NUMERIC)
|
||||
{
|
||||
}
|
||||
|
||||
json_event_filter_check::alias::alias(nlohmann::json::json_pointer ptr)
|
||||
: m_jptr(ptr), m_format(def_format),
|
||||
m_idx_mode(IDX_NONE), m_idx_type(IDX_NUMERIC)
|
||||
json_event_filter_check::alias::alias(nlohmann::json::json_pointer ptr):
|
||||
m_jptr(ptr), m_format(def_format)
|
||||
{
|
||||
}
|
||||
|
||||
json_event_filter_check::alias::alias(nlohmann::json::json_pointer ptr,
|
||||
format_t format)
|
||||
: m_jptr(ptr), m_format(format),
|
||||
m_idx_mode(IDX_NONE), m_idx_type(IDX_NUMERIC)
|
||||
{
|
||||
}
|
||||
|
||||
json_event_filter_check::alias::alias(nlohmann::json::json_pointer ptr,
|
||||
format_t format,
|
||||
index_mode mode,
|
||||
index_type itype)
|
||||
: m_jptr(ptr), m_format(format),
|
||||
m_idx_mode(mode), m_idx_type(itype)
|
||||
format_t format):
|
||||
m_jptr(ptr),
|
||||
m_format(format)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -101,8 +125,8 @@ json_event_filter_check::alias::~alias()
|
||||
{
|
||||
}
|
||||
|
||||
json_event_filter_check::json_event_filter_check()
|
||||
: m_format(def_format)
|
||||
json_event_filter_check::json_event_filter_check():
|
||||
m_format(def_format)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -118,18 +142,25 @@ int32_t json_event_filter_check::parse_field_name(const char *str, bool alloc_st
|
||||
|
||||
size_t idx_len = 0;
|
||||
|
||||
for(auto &pair : m_aliases)
|
||||
for(auto &info : m_info.m_fields)
|
||||
{
|
||||
// What follows the match must not be alphanumeric or a dot
|
||||
if(strncmp(pair.first.c_str(), str, pair.first.size()) == 0 &&
|
||||
!isalnum((int) str[pair.first.size()]) &&
|
||||
str[pair.first.size()] != '.' &&
|
||||
pair.first.size() > match_len)
|
||||
if(m_aliases.find(info.m_name) == m_aliases.end())
|
||||
{
|
||||
m_jptr = pair.second.m_jptr;
|
||||
m_field = pair.first;
|
||||
m_format = pair.second.m_format;
|
||||
match_len = pair.first.size();
|
||||
throw falco_exception("Could not find alias for field name " + info.m_name);
|
||||
}
|
||||
|
||||
auto &al = m_aliases[info.m_name];
|
||||
|
||||
// What follows the match must not be alphanumeric or a dot
|
||||
if(strncmp(info.m_name.c_str(), str, info.m_name.size()) == 0 &&
|
||||
!isalnum((int)str[info.m_name.size()]) &&
|
||||
str[info.m_name.size()] != '.' &&
|
||||
info.m_name.size() > match_len)
|
||||
{
|
||||
m_jptr = al.m_jptr;
|
||||
m_field = info.m_name;
|
||||
m_format = al.m_format;
|
||||
match_len = info.m_name.size();
|
||||
|
||||
const char *start = str + m_field.size();
|
||||
|
||||
@@ -141,24 +172,24 @@ int32_t json_event_filter_check::parse_field_name(const char *str, bool alloc_st
|
||||
|
||||
if(end != NULL)
|
||||
{
|
||||
m_idx = string(start, end-start);
|
||||
m_idx = string(start, end - start);
|
||||
}
|
||||
|
||||
idx_len = (end - start + 2);
|
||||
}
|
||||
|
||||
if(m_idx.empty() && pair.second.m_idx_mode == alias::IDX_REQUIRED)
|
||||
if(m_idx.empty() && info.m_idx_mode == IDX_REQUIRED)
|
||||
{
|
||||
throw falco_exception(string("When parsing filtercheck ") + string(str) + string(": ") + m_field + string(" requires an index but none provided"));
|
||||
}
|
||||
|
||||
if(!m_idx.empty() && pair.second.m_idx_mode == alias::IDX_NONE)
|
||||
if(!m_idx.empty() && info.m_idx_mode == IDX_NONE)
|
||||
{
|
||||
throw falco_exception(string("When parsing filtercheck ") + string(str) + string(": ") + m_field + string(" forbids an index but one provided"));
|
||||
}
|
||||
|
||||
if(!m_idx.empty() &&
|
||||
pair.second.m_idx_type == alias::IDX_NUMERIC &&
|
||||
info.m_idx_type == IDX_NUMERIC &&
|
||||
m_idx.find_first_not_of("0123456789") != string::npos)
|
||||
{
|
||||
throw falco_exception(string("When parsing filtercheck ") + string(str) + string(": ") + m_field + string(" requires a numeric index"));
|
||||
@@ -169,14 +200,14 @@ int32_t json_event_filter_check::parse_field_name(const char *str, bool alloc_st
|
||||
return match_len + idx_len;
|
||||
}
|
||||
|
||||
void json_event_filter_check::add_filter_value(const char* str, uint32_t len, uint32_t i)
|
||||
void json_event_filter_check::add_filter_value(const char *str, uint32_t len, uint32_t i)
|
||||
{
|
||||
m_values.push_back(string(str));
|
||||
}
|
||||
|
||||
bool json_event_filter_check::compare(gen_event *evt)
|
||||
{
|
||||
json_event *jevt = (json_event *) evt;
|
||||
json_event *jevt = (json_event *)evt;
|
||||
|
||||
std::string value = extract(jevt);
|
||||
|
||||
@@ -197,7 +228,7 @@ bool json_event_filter_check::compare(gen_event *evt)
|
||||
case CO_IN:
|
||||
for(auto &val : m_values)
|
||||
{
|
||||
if (value == val)
|
||||
if(value == val)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -240,11 +271,12 @@ json_event_filter_check::check_info &json_event_filter_check::get_fields()
|
||||
return m_info;
|
||||
}
|
||||
|
||||
uint8_t* json_event_filter_check::extract(gen_event *evt, uint32_t* len, bool sanitize_strings)
|
||||
uint8_t *json_event_filter_check::extract(gen_event *evt, uint32_t *len, bool sanitize_strings)
|
||||
{
|
||||
json_event *jevt = (json_event *) evt;
|
||||
json_event *jevt = (json_event *)evt;
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
const json &j = jevt->jevt().at(m_jptr);
|
||||
|
||||
// Only format when the value was actually found in
|
||||
@@ -258,7 +290,7 @@ uint8_t* json_event_filter_check::extract(gen_event *evt, uint32_t* len, bool sa
|
||||
|
||||
*len = m_tstr.size();
|
||||
|
||||
return (uint8_t *) m_tstr.c_str();
|
||||
return (uint8_t *)m_tstr.c_str();
|
||||
}
|
||||
|
||||
std::string json_event_filter_check::extract(json_event *evt)
|
||||
@@ -271,7 +303,7 @@ std::string json_event_filter_check::extract(json_event *evt)
|
||||
|
||||
if(res != NULL)
|
||||
{
|
||||
ret.assign((const char *) res, len);
|
||||
ret.assign((const char *)res, len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -287,18 +319,15 @@ jevt_filter_check::jevt_filter_check()
|
||||
{
|
||||
m_info = {"jevt",
|
||||
"generic ways to access json events",
|
||||
{
|
||||
{s_jevt_time_field, "json event timestamp as a string that includes the nanosecond part"},
|
||||
{s_jevt_time_iso_8601_field, "json event timestamp in ISO 8601 format, including nanoseconds and time zone offset (in UTC)"},
|
||||
{s_jevt_rawtime_field, "absolute event timestamp, i.e. nanoseconds from epoch."},
|
||||
{s_jevt_value_field, "General way to access single property from json object. The syntax is [<json pointer expression>]. The property is returned as a string"},
|
||||
{s_jevt_obj_field, "The entire json object, stringified"}
|
||||
}};
|
||||
{{s_jevt_time_field, "json event timestamp as a string that includes the nanosecond part"},
|
||||
{s_jevt_time_iso_8601_field, "json event timestamp in ISO 8601 format, including nanoseconds and time zone offset (in UTC)"},
|
||||
{s_jevt_rawtime_field, "absolute event timestamp, i.e. nanoseconds from epoch."},
|
||||
{s_jevt_value_field, "General way to access single property from json object. The syntax is [<json pointer expression>]. The property is returned as a string", IDX_REQUIRED, IDX_KEY},
|
||||
{s_jevt_obj_field, "The entire json object, stringified"}}};
|
||||
}
|
||||
|
||||
jevt_filter_check::~jevt_filter_check()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int32_t jevt_filter_check::parse_field_name(const char *str, bool alloc_state, bool needed_for_filtering)
|
||||
@@ -332,55 +361,56 @@ int32_t jevt_filter_check::parse_field_name(const char *str, bool alloc_state, b
|
||||
const char *end;
|
||||
|
||||
// What follows must be [<json pointer expression>]
|
||||
if (*(str + s_jevt_value_field.size()) != '[' ||
|
||||
((end = strchr(str + 1, ']')) == NULL))
|
||||
if(*(str + s_jevt_value_field.size()) != '[' ||
|
||||
((end = strchr(str + 1, ']')) == NULL))
|
||||
|
||||
{
|
||||
throw falco_exception(string("Could not parse filtercheck field \"") + str + "\". Did not have expected format with 'jevt.value[<json pointer>]'");
|
||||
}
|
||||
|
||||
try {
|
||||
m_jptr = json::json_pointer(string(str + (s_jevt_value_field.size()+1), (end-str-(s_jevt_value_field.size()+1))));
|
||||
try
|
||||
{
|
||||
m_jptr = json::json_pointer(string(str + (s_jevt_value_field.size() + 1), (end - str - (s_jevt_value_field.size() + 1))));
|
||||
}
|
||||
catch (json::parse_error& e)
|
||||
catch(json::parse_error &e)
|
||||
{
|
||||
throw falco_exception(string("Could not parse filtercheck field \"") + str + "\". Invalid json selector (" + e.what() + ")");
|
||||
}
|
||||
|
||||
// The +1 accounts for the closing ']'
|
||||
m_field = string(str, end-str + 1);
|
||||
m_field = string(str, end - str + 1);
|
||||
return (end - str + 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t* jevt_filter_check::extract(gen_event *evt, uint32_t* len, bool sanitize_stings)
|
||||
uint8_t *jevt_filter_check::extract(gen_event *evt, uint32_t *len, bool sanitize_stings)
|
||||
{
|
||||
if(m_field == s_jevt_rawtime_field)
|
||||
{
|
||||
m_tstr = to_string(evt->get_ts());
|
||||
*len = m_tstr.size();
|
||||
return (uint8_t *) m_tstr.c_str();
|
||||
return (uint8_t *)m_tstr.c_str();
|
||||
}
|
||||
else if(m_field == s_jevt_time_field)
|
||||
{
|
||||
sinsp_utils::ts_to_string(evt->get_ts(), &m_tstr, false, true);
|
||||
*len = m_tstr.size();
|
||||
return (uint8_t *) m_tstr.c_str();
|
||||
return (uint8_t *)m_tstr.c_str();
|
||||
}
|
||||
else if(m_field == s_jevt_time_iso_8601_field)
|
||||
{
|
||||
sinsp_utils::ts_to_iso_8601(evt->get_ts(), &m_tstr);
|
||||
*len = m_tstr.size();
|
||||
return (uint8_t *) m_tstr.c_str();
|
||||
return (uint8_t *)m_tstr.c_str();
|
||||
}
|
||||
else if(m_field == s_jevt_obj_field)
|
||||
{
|
||||
json_event *jevt = (json_event *) evt;
|
||||
json_event *jevt = (json_event *)evt;
|
||||
m_tstr = jevt->jevt().dump();
|
||||
*len = m_tstr.size();
|
||||
return (uint8_t *) m_tstr.c_str();
|
||||
return (uint8_t *)m_tstr.c_str();
|
||||
}
|
||||
|
||||
return json_event_filter_check::extract(evt, len, sanitize_stings);
|
||||
@@ -390,7 +420,7 @@ json_event_filter_check *jevt_filter_check::allocate_new()
|
||||
{
|
||||
jevt_filter_check *chk = new jevt_filter_check();
|
||||
|
||||
return (json_event_filter_check *) chk;
|
||||
return (json_event_filter_check *)chk;
|
||||
}
|
||||
|
||||
std::string k8s_audit_filter_check::index_image(const json &j, std::string &field, std::string &idx)
|
||||
@@ -399,8 +429,9 @@ std::string k8s_audit_filter_check::index_image(const json &j, std::string &fiel
|
||||
|
||||
string image;
|
||||
|
||||
try {
|
||||
image = j[idx_num].at("image");
|
||||
try
|
||||
{
|
||||
image = j[idx_num].at("image");
|
||||
}
|
||||
catch(json::out_of_range &e)
|
||||
{
|
||||
@@ -442,7 +473,6 @@ std::string k8s_audit_filter_check::index_has_name(const json &j, std::string &f
|
||||
return string("false");
|
||||
}
|
||||
|
||||
|
||||
std::string k8s_audit_filter_check::index_query_param(const json &j, std::string &field, std::string &idx)
|
||||
{
|
||||
string uri = j;
|
||||
@@ -461,7 +491,7 @@ std::string k8s_audit_filter_check::index_query_param(const json &j, std::string
|
||||
{
|
||||
std::vector<std::string> param_parts = sinsp_split(part, '=');
|
||||
|
||||
if(param_parts.size() == 2 && uri::decode(param_parts[0], true)==idx)
|
||||
if(param_parts.size() == 2 && uri::decode(param_parts[0], true) == idx)
|
||||
{
|
||||
return uri::decode(param_parts[1]);
|
||||
}
|
||||
@@ -470,7 +500,6 @@ std::string k8s_audit_filter_check::index_query_param(const json &j, std::string
|
||||
return string("<NA>");
|
||||
}
|
||||
|
||||
|
||||
std::string k8s_audit_filter_check::index_generic(const json &j, std::string &field, std::string &idx)
|
||||
{
|
||||
json item;
|
||||
@@ -483,7 +512,8 @@ std::string k8s_audit_filter_check::index_generic(const json &j, std::string &fi
|
||||
{
|
||||
uint64_t idx_num = (idx.empty() ? 0 : stoi(idx));
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
item = j[idx_num];
|
||||
}
|
||||
catch(json::out_of_range &e)
|
||||
@@ -501,7 +531,7 @@ std::string k8s_audit_filter_check::index_select(const json &j, std::string &fie
|
||||
|
||||
// Use the suffix of the field to determine which property to
|
||||
// select from each object.
|
||||
std::string prop = field.substr(field.find_last_of(".")+1);
|
||||
std::string prop = field.substr(field.find_last_of(".") + 1);
|
||||
|
||||
std::string ret;
|
||||
|
||||
@@ -514,7 +544,8 @@ std::string k8s_audit_filter_check::index_select(const json &j, std::string &fie
|
||||
ret += " ";
|
||||
}
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
ret += json_event_filter_check::json_as_string(obj.at(prop));
|
||||
}
|
||||
catch(json::out_of_range &e)
|
||||
@@ -525,7 +556,8 @@ std::string k8s_audit_filter_check::index_select(const json &j, std::string &fie
|
||||
}
|
||||
else
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
ret = j[stoi(idx)].at(prop);
|
||||
}
|
||||
catch(json::out_of_range &e)
|
||||
@@ -545,7 +577,8 @@ std::string k8s_audit_filter_check::index_privileged(const json &j, std::string
|
||||
|
||||
if(!idx.empty())
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
privileged = j[stoi(idx)].at(jpriv);
|
||||
}
|
||||
catch(json::out_of_range &e)
|
||||
@@ -556,7 +589,8 @@ std::string k8s_audit_filter_check::index_privileged(const json &j, std::string
|
||||
{
|
||||
for(auto &container : j)
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
if(container.at(jpriv))
|
||||
{
|
||||
privileged = true;
|
||||
@@ -593,46 +627,43 @@ k8s_audit_filter_check::k8s_audit_filter_check()
|
||||
{
|
||||
m_info = {"ka",
|
||||
"Access K8s Audit Log Events",
|
||||
{
|
||||
{"ka.auditid", "The unique id of the audit event"},
|
||||
{"ka.stage", "Stage of the request (e.g. RequestReceived, ResponseComplete, etc.)"},
|
||||
{"ka.auth.decision", "The authorization decision"},
|
||||
{"ka.auth.reason", "The authorization reason"},
|
||||
{"ka.user.name", "The user name performing the request"},
|
||||
{"ka.user.groups", "The groups to which the user belongs"},
|
||||
{"ka.impuser.name", "The impersonated user name"},
|
||||
{"ka.verb", "The action being performed"},
|
||||
{"ka.uri", "The request URI as sent from client to server"},
|
||||
{"ka.uri.param", "The value of a given query parameter in the uri (e.g. when uri=/foo?key=val, ka.uri.param[key] is val)."},
|
||||
{"ka.target.name", "The target object name"},
|
||||
{"ka.target.namespace", "The target object namespace"},
|
||||
{"ka.target.resource", "The target object resource"},
|
||||
{"ka.target.subresource", "The target object subresource"},
|
||||
{"ka.req.binding.subjects", "When the request object refers to a cluster role binding, the subject (e.g. account/users) being linked by the binding"},
|
||||
{"ka.req.binding.subject.has_name", "When the request object refers to a cluster role binding, return true if a subject with the provided name exists"},
|
||||
{"ka.req.binding.role", "When the request object refers to a cluster role binding, the role being linked by the binding"},
|
||||
{"ka.req.configmap.name", "If the request object refers to a configmap, the configmap name"},
|
||||
{"ka.req.configmap.obj", "If the request object refers to a configmap, the entire configmap object"},
|
||||
{"ka.req.container.image", "When the request object refers to a container, the container's images. Can be indexed (e.g. ka.req.container.image[0]). Without any index, returns the first image"},
|
||||
{"ka.req.container.image.repository", "The same as req.container.image, but only the repository part (e.g. sysdig/falco)"},
|
||||
{"ka.req.container.host_network", "When the request object refers to a container, the value of the hostNetwork flag."},
|
||||
{"ka.req.container.privileged", "When the request object refers to a container, whether or not any container is run privileged. With an index, return whether or not the ith container is run privileged."},
|
||||
{"ka.req.role.rules", "When the request object refers to a role/cluster role, the rules associated with the role"},
|
||||
{"ka.req.role.rules.apiGroups", "When the request object refers to a role/cluster role, the api groups associated with the role's rules. With an index, return only the api groups from the ith rule. Without an index, return all api groups concatenated"},
|
||||
{"ka.req.role.rules.nonResourceURLs", "When the request object refers to a role/cluster role, the non resource urls associated with the role's rules. With an index, return only the non resource urls from the ith rule. Without an index, return all non resource urls concatenated"},
|
||||
{"ka.req.role.rules.verbs", "When the request object refers to a role/cluster role, the verbs associated with the role's rules. With an index, return only the verbs from the ith rule. Without an index, return all verbs concatenated"},
|
||||
{"ka.req.role.rules.resources", "When the request object refers to a role/cluster role, the resources associated with the role's rules. With an index, return only the resources from the ith rule. Without an index, return all resources concatenated"},
|
||||
{"ka.req.service.type", "When the request object refers to a service, the service type"},
|
||||
{"ka.req.service.ports", "When the request object refers to a service, the service's ports. Can be indexed (e.g. ka.req.service.ports[0]). Without any index, returns all ports"},
|
||||
{"ka.req.volume.hostpath", "If the request object contains volume definitions, whether or not a hostPath volume exists that mounts the specified path from the host (...hostpath[/etc]=true if a volume mounts /etc from the host). The index can be a glob, in which case all volumes are considered to find any path matching the specified glob (...hostpath[/usr/*] would match either /usr/local or /usr/bin)"},
|
||||
{"ka.resp.name", "The response object name"},
|
||||
{"ka.response.code", "The response code"},
|
||||
{"ka.response.reason", "The response reason (usually present only for failures)"}
|
||||
}};
|
||||
{{"ka.auditid", "The unique id of the audit event"},
|
||||
{"ka.stage", "Stage of the request (e.g. RequestReceived, ResponseComplete, etc.)"},
|
||||
{"ka.auth.decision", "The authorization decision"},
|
||||
{"ka.auth.reason", "The authorization reason"},
|
||||
{"ka.user.name", "The user name performing the request"},
|
||||
{"ka.user.groups", "The groups to which the user belongs"},
|
||||
{"ka.impuser.name", "The impersonated user name"},
|
||||
{"ka.verb", "The action being performed"},
|
||||
{"ka.uri", "The request URI as sent from client to server"},
|
||||
{"ka.uri.param", "The value of a given query parameter in the uri (e.g. when uri=/foo?key=val, ka.uri.param[key] is val).", IDX_REQUIRED, IDX_KEY},
|
||||
{"ka.target.name", "The target object name"},
|
||||
{"ka.target.namespace", "The target object namespace"},
|
||||
{"ka.target.resource", "The target object resource"},
|
||||
{"ka.target.subresource", "The target object subresource"},
|
||||
{"ka.req.binding.subjects", "When the request object refers to a cluster role binding, the subject (e.g. account/users) being linked by the binding"},
|
||||
{"ka.req.binding.subject.has_name", "When the request object refers to a cluster role binding, return true if a subject with the provided name exists", IDX_REQUIRED, IDX_KEY},
|
||||
{"ka.req.binding.role", "When the request object refers to a cluster role binding, the role being linked by the binding"},
|
||||
{"ka.req.configmap.name", "If the request object refers to a configmap, the configmap name"},
|
||||
{"ka.req.configmap.obj", "If the request object refers to a configmap, the entire configmap object"},
|
||||
{"ka.req.container.image", "When the request object refers to a container, the container's images. Can be indexed (e.g. ka.req.container.image[0]). Without any index, returns the first image", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.container.image.repository", "The same as req.container.image, but only the repository part (e.g. sysdig/falco)", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.container.host_network", "When the request object refers to a container, the value of the hostNetwork flag."},
|
||||
{"ka.req.container.privileged", "When the request object refers to a container, whether or not any container is run privileged. With an index, return whether or not the ith container is run privileged.", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.role.rules", "When the request object refers to a role/cluster role, the rules associated with the role"},
|
||||
{"ka.req.role.rules.apiGroups", "When the request object refers to a role/cluster role, the api groups associated with the role's rules. With an index, return only the api groups from the ith rule. Without an index, return all api groups concatenated", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.role.rules.nonResourceURLs", "When the request object refers to a role/cluster role, the non resource urls associated with the role's rules. With an index, return only the non resource urls from the ith rule. Without an index, return all non resource urls concatenated", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.role.rules.verbs", "When the request object refers to a role/cluster role, the verbs associated with the role's rules. With an index, return only the verbs from the ith rule. Without an index, return all verbs concatenated", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.role.rules.resources", "When the request object refers to a role/cluster role, the resources associated with the role's rules. With an index, return only the resources from the ith rule. Without an index, return all resources concatenated", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.service.type", "When the request object refers to a service, the service type"},
|
||||
{"ka.req.service.ports", "When the request object refers to a service, the service's ports. Can be indexed (e.g. ka.req.service.ports[0]). Without any index, returns all ports", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.volume.hostpath", "If the request object contains volume definitions, whether or not a hostPath volume exists that mounts the specified path from the host (...hostpath[/etc]=true if a volume mounts /etc from the host). The index can be a glob, in which case all volumes are considered to find any path matching the specified glob (...hostpath[/usr/*] would match either /usr/local or /usr/bin)", IDX_REQUIRED, IDX_KEY},
|
||||
{"ka.resp.name", "The response object name"},
|
||||
{"ka.response.code", "The response code"},
|
||||
{"ka.response.reason", "The response reason (usually present only for failures)"},
|
||||
{"ka.useragent", "The useragent of the client who made the request to the apiserver"}}};
|
||||
|
||||
{
|
||||
using a = alias;
|
||||
|
||||
m_aliases = {
|
||||
{"ka.auditid", {"/auditID"_json_pointer}},
|
||||
{"ka.stage", {"/stage"_json_pointer}},
|
||||
@@ -643,45 +674,44 @@ k8s_audit_filter_check::k8s_audit_filter_check()
|
||||
{"ka.impuser.name", {"/impersonatedUser/username"_json_pointer}},
|
||||
{"ka.verb", {"/verb"_json_pointer}},
|
||||
{"ka.uri", {"/requestURI"_json_pointer}},
|
||||
{"ka.uri.param", {"/requestURI"_json_pointer, index_query_param, a::IDX_REQUIRED, a::IDX_KEY}},
|
||||
{"ka.uri.param", {"/requestURI"_json_pointer, index_query_param}},
|
||||
{"ka.target.name", {"/objectRef/name"_json_pointer}},
|
||||
{"ka.target.namespace", {"/objectRef/namespace"_json_pointer}},
|
||||
{"ka.target.resource", {"/objectRef/resource"_json_pointer}},
|
||||
{"ka.target.subresource", {"/objectRef/subresource"_json_pointer}},
|
||||
{"ka.req.binding.subjects", {"/requestObject/subjects"_json_pointer}},
|
||||
{"ka.req.binding.subject.has_name", {"/requestObject/subjects"_json_pointer, index_has_name, a::IDX_REQUIRED, a::IDX_KEY}},
|
||||
{"ka.req.binding.subject.has_name", {"/requestObject/subjects"_json_pointer, index_has_name}},
|
||||
{"ka.req.binding.role", {"/requestObject/roleRef/name"_json_pointer}},
|
||||
{"ka.req.configmap.name", {"/objectRef/name"_json_pointer}},
|
||||
{"ka.req.configmap.obj", {"/requestObject/data"_json_pointer}},
|
||||
{"ka.req.container.image", {"/requestObject/spec/containers"_json_pointer, index_image, a::IDX_ALLOWED, a::IDX_NUMERIC}},
|
||||
{"ka.req.container.image.repository", {"/requestObject/spec/containers"_json_pointer, index_image, a::IDX_ALLOWED, a::IDX_NUMERIC}},
|
||||
{"ka.req.container.image", {"/requestObject/spec/containers"_json_pointer, index_image}},
|
||||
{"ka.req.container.image.repository", {"/requestObject/spec/containers"_json_pointer, index_image}},
|
||||
{"ka.req.container.host_network", {"/requestObject/spec/hostNetwork"_json_pointer}},
|
||||
{"ka.req.container.privileged", {"/requestObject/spec/containers"_json_pointer, index_privileged, a::IDX_ALLOWED, a::IDX_NUMERIC}},
|
||||
{"ka.req.container.privileged", {"/requestObject/spec/containers"_json_pointer, index_privileged}},
|
||||
{"ka.req.role.rules", {"/requestObject/rules"_json_pointer}},
|
||||
{"ka.req.role.rules.apiGroups", {"/requestObject/rules"_json_pointer, index_select, a::IDX_ALLOWED, a::IDX_NUMERIC}},
|
||||
{"ka.req.role.rules.nonResourceURLs", {"/requestObject/rules"_json_pointer, index_select, a::IDX_ALLOWED, a::IDX_NUMERIC}},
|
||||
{"ka.req.role.rules.resources", {"/requestObject/rules"_json_pointer, index_select, a::IDX_ALLOWED, a::IDX_NUMERIC}},
|
||||
{"ka.req.role.rules.verbs", {"/requestObject/rules"_json_pointer, index_select, a::IDX_ALLOWED, a::IDX_NUMERIC}},
|
||||
{"ka.req.role.rules.apiGroups", {"/requestObject/rules"_json_pointer, index_select}},
|
||||
{"ka.req.role.rules.nonResourceURLs", {"/requestObject/rules"_json_pointer, index_select}},
|
||||
{"ka.req.role.rules.resources", {"/requestObject/rules"_json_pointer, index_select}},
|
||||
{"ka.req.role.rules.verbs", {"/requestObject/rules"_json_pointer, index_select}},
|
||||
{"ka.req.service.type", {"/requestObject/spec/type"_json_pointer}},
|
||||
{"ka.req.service.ports", {"/requestObject/spec/ports"_json_pointer, index_generic, a::IDX_ALLOWED, a::IDX_NUMERIC}},
|
||||
{"ka.req.volume.hostpath", {"/requestObject/spec/volumes"_json_pointer, check_hostpath_vols, a::IDX_REQUIRED, a::IDX_KEY}},
|
||||
{"ka.req.service.ports", {"/requestObject/spec/ports"_json_pointer, index_generic}},
|
||||
{"ka.req.volume.hostpath", {"/requestObject/spec/volumes"_json_pointer, check_hostpath_vols}},
|
||||
{"ka.resp.name", {"/responseObject/metadata/name"_json_pointer}},
|
||||
{"ka.response.code", {"/responseStatus/code"_json_pointer}},
|
||||
{"ka.response.reason", {"/responseStatus/reason"_json_pointer}}
|
||||
};
|
||||
{"ka.response.reason", {"/responseStatus/reason"_json_pointer}},
|
||||
{"ka.useragent", {"/userAgent"_json_pointer}}};
|
||||
}
|
||||
}
|
||||
|
||||
k8s_audit_filter_check::~k8s_audit_filter_check()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
json_event_filter_check *k8s_audit_filter_check::allocate_new()
|
||||
{
|
||||
k8s_audit_filter_check *chk = new k8s_audit_filter_check();
|
||||
|
||||
return (json_event_filter_check *) chk;
|
||||
return (json_event_filter_check *)chk;
|
||||
}
|
||||
|
||||
json_event_filter::json_event_filter()
|
||||
@@ -736,9 +766,9 @@ std::list<json_event_filter_check::check_info> &json_event_filter_factory::get_f
|
||||
return m_info;
|
||||
}
|
||||
|
||||
json_event_formatter::json_event_formatter(json_event_filter_factory &json_factory, std::string &format)
|
||||
: m_format(format),
|
||||
m_json_factory(json_factory)
|
||||
json_event_formatter::json_event_formatter(json_event_filter_factory &json_factory, std::string &format):
|
||||
m_format(format),
|
||||
m_json_factory(json_factory)
|
||||
{
|
||||
parse_format();
|
||||
}
|
||||
@@ -751,7 +781,7 @@ std::string json_event_formatter::tostring(json_event *ev)
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
std::list<std::pair<std::string,std::string>> resolved;
|
||||
std::list<std::pair<std::string, std::string>> resolved;
|
||||
|
||||
resolve_tokens(ev, resolved);
|
||||
|
||||
@@ -767,7 +797,7 @@ std::string json_event_formatter::tojson(json_event *ev)
|
||||
{
|
||||
nlohmann::json ret;
|
||||
|
||||
std::list<std::pair<std::string,std::string>> resolved;
|
||||
std::list<std::pair<std::string, std::string>> resolved;
|
||||
|
||||
resolve_tokens(ev, resolved);
|
||||
|
||||
@@ -802,11 +832,11 @@ void json_event_formatter::parse_format()
|
||||
{
|
||||
// Skip the %
|
||||
tformat.erase(0, 1);
|
||||
json_event_filter_check *chk = (json_event_filter_check *) m_json_factory.new_filtercheck(tformat.c_str());
|
||||
json_event_filter_check *chk = (json_event_filter_check *)m_json_factory.new_filtercheck(tformat.c_str());
|
||||
|
||||
if(!chk)
|
||||
{
|
||||
throw falco_exception(string ("Could not parse format string \"") + m_format + "\": unknown filtercheck field " + tformat);
|
||||
throw falco_exception(string("Could not parse format string \"") + m_format + "\": unknown filtercheck field " + tformat);
|
||||
}
|
||||
|
||||
size = chk->parsed_size();
|
||||
@@ -826,7 +856,7 @@ void json_event_formatter::parse_format()
|
||||
// Empty fields are only allowed at the beginning of the string
|
||||
if(m_tokens.size() > 0)
|
||||
{
|
||||
throw falco_exception(string ("Could not parse format string \"" + m_format + "\": empty filtercheck field"));
|
||||
throw falco_exception(string("Could not parse format string \"" + m_format + "\": empty filtercheck field"));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -838,7 +868,7 @@ void json_event_formatter::parse_format()
|
||||
}
|
||||
}
|
||||
|
||||
void json_event_formatter::resolve_tokens(json_event *ev, std::list<std::pair<std::string,std::string>> &resolved)
|
||||
void json_event_formatter::resolve_tokens(json_event *ev, std::list<std::pair<std::string, std::string>> &resolved)
|
||||
{
|
||||
for(auto tok : m_tokens)
|
||||
{
|
||||
|
||||
@@ -62,19 +62,40 @@ protected:
|
||||
class json_event_filter_check : public gen_event_filter_check
|
||||
{
|
||||
public:
|
||||
enum index_mode {
|
||||
IDX_REQUIRED,
|
||||
IDX_ALLOWED,
|
||||
IDX_NONE
|
||||
};
|
||||
|
||||
enum index_type {
|
||||
IDX_KEY,
|
||||
IDX_NUMERIC
|
||||
};
|
||||
|
||||
// A struct describing a single filtercheck field ("ka.user")
|
||||
struct field_info {
|
||||
std::string name;
|
||||
std::string desc;
|
||||
std::string m_name;
|
||||
std::string m_desc;
|
||||
|
||||
index_mode m_idx_mode;
|
||||
index_type m_idx_type;
|
||||
// The variants allow for brace-initialization either
|
||||
// with just the name/desc or additionally with index
|
||||
// information
|
||||
field_info();
|
||||
field_info(std::string name, std::string desc);
|
||||
field_info(std::string name, std::string desc, index_mode mode);
|
||||
field_info(std::string name, std::string desc, index_mode mode, index_type itype);
|
||||
virtual ~field_info();
|
||||
};
|
||||
|
||||
// A struct describing a group of filtercheck fields ("ka")
|
||||
struct check_info {
|
||||
std::string name;
|
||||
std::string desc;
|
||||
std::string m_name;
|
||||
std::string m_desc;
|
||||
|
||||
std::list<field_info> fields;
|
||||
std::list<field_info> m_fields;
|
||||
};
|
||||
|
||||
json_event_filter_check();
|
||||
@@ -115,28 +136,12 @@ protected:
|
||||
typedef std::function<std::string (const nlohmann::json &, std::string &field, std::string &idx)> format_t;
|
||||
|
||||
struct alias {
|
||||
|
||||
// Whether this alias requires an index, allows an
|
||||
// index, or should not have an index.
|
||||
enum index_mode {
|
||||
IDX_REQUIRED,
|
||||
IDX_ALLOWED,
|
||||
IDX_NONE
|
||||
};
|
||||
|
||||
enum index_type {
|
||||
IDX_KEY,
|
||||
IDX_NUMERIC
|
||||
};
|
||||
|
||||
// The variants allow for brace-initialization either
|
||||
// with just the pointer or with both the pointer and
|
||||
// a format function.
|
||||
alias();
|
||||
alias(nlohmann::json::json_pointer ptr);
|
||||
alias(nlohmann::json::json_pointer ptr, format_t format);
|
||||
alias(nlohmann::json::json_pointer ptr, format_t format, index_mode mode);
|
||||
alias(nlohmann::json::json_pointer ptr, format_t format, index_mode mode, index_type itype);
|
||||
virtual ~alias();
|
||||
|
||||
// A json pointer used to extract a referenced value
|
||||
@@ -149,10 +154,6 @@ protected:
|
||||
// indexing, searches, etc.) or string reformatting to
|
||||
// trim unnecessary parts of the value.
|
||||
format_t m_format;
|
||||
|
||||
index_mode m_idx_mode;
|
||||
|
||||
index_type m_idx_type;
|
||||
};
|
||||
|
||||
// This map defines the aliases defined by this filter check
|
||||
|
||||
@@ -62,12 +62,12 @@ function expand_macros(ast, defs, changed)
|
||||
elseif ast.type == "Filter" then
|
||||
if (ast.value.type == "Macro") then
|
||||
if (defs[ast.value.value] == nil) then
|
||||
error("Undefined macro '".. ast.value.value .. "' used in filter.")
|
||||
return false, "Undefined macro '".. ast.value.value .. "' used in filter."
|
||||
end
|
||||
defs[ast.value.value].used = true
|
||||
ast.value = copy_ast_obj(defs[ast.value.value].ast)
|
||||
changed = true
|
||||
return changed
|
||||
return true, changed
|
||||
end
|
||||
return expand_macros(ast.value, defs, changed)
|
||||
|
||||
@@ -75,7 +75,7 @@ function expand_macros(ast, defs, changed)
|
||||
|
||||
if (ast.left.type == "Macro") then
|
||||
if (defs[ast.left.value] == nil) then
|
||||
error("Undefined macro '".. ast.left.value .. "' used in filter.")
|
||||
return false, "Undefined macro '".. ast.left.value .. "' used in filter."
|
||||
end
|
||||
defs[ast.left.value].used = true
|
||||
ast.left = copy_ast_obj(defs[ast.left.value].ast)
|
||||
@@ -84,21 +84,27 @@ function expand_macros(ast, defs, changed)
|
||||
|
||||
if (ast.right.type == "Macro") then
|
||||
if (defs[ast.right.value] == nil) then
|
||||
error("Undefined macro ".. ast.right.value .. " used in filter.")
|
||||
return false, "Undefined macro ".. ast.right.value .. " used in filter."
|
||||
end
|
||||
defs[ast.right.value].used = true
|
||||
ast.right = copy_ast_obj(defs[ast.right.value].ast)
|
||||
changed = true
|
||||
end
|
||||
|
||||
local changed_left = expand_macros(ast.left, defs, false)
|
||||
local changed_right = expand_macros(ast.right, defs, false)
|
||||
return changed or changed_left or changed_right
|
||||
local status, changed_left = expand_macros(ast.left, defs, false)
|
||||
if status == false then
|
||||
return false, changed_left
|
||||
end
|
||||
local status, changed_right = expand_macros(ast.right, defs, false)
|
||||
if status == false then
|
||||
return false, changed_right
|
||||
end
|
||||
return true, changed or changed_left or changed_right
|
||||
|
||||
elseif ast.type == "UnaryBoolOp" then
|
||||
if (ast.argument.type == "Macro") then
|
||||
if (defs[ast.argument.value] == nil) then
|
||||
error("Undefined macro ".. ast.argument.value .. " used in filter.")
|
||||
return false, "Undefined macro ".. ast.argument.value .. " used in filter."
|
||||
end
|
||||
defs[ast.argument.value].used = true
|
||||
ast.argument = copy_ast_obj(defs[ast.argument.value].ast)
|
||||
@@ -106,7 +112,7 @@ function expand_macros(ast, defs, changed)
|
||||
end
|
||||
return expand_macros(ast.argument, defs, changed)
|
||||
end
|
||||
return changed
|
||||
return true, changed
|
||||
end
|
||||
|
||||
function get_macros(ast, set)
|
||||
@@ -152,16 +158,35 @@ end
|
||||
function compiler.expand_lists_in(source, list_defs)
|
||||
|
||||
for name, def in pairs(list_defs) do
|
||||
local begin_name_pat = "^("..name..")([%s(),=])"
|
||||
local mid_name_pat = "([%s(),=])("..name..")([%s(),=])"
|
||||
local end_name_pat = "([%s(),=])("..name..")$"
|
||||
|
||||
source, subcount1 = string.gsub(source, begin_name_pat, table.concat(def.items, ", ").."%2")
|
||||
source, subcount2 = string.gsub(source, mid_name_pat, "%1"..table.concat(def.items, ", ").."%3")
|
||||
source, subcount3 = string.gsub(source, end_name_pat, "%1"..table.concat(def.items, ", "))
|
||||
local bpos = string.find(source, name, 1, true)
|
||||
|
||||
if (subcount1 + subcount2 + subcount3) > 0 then
|
||||
while bpos ~= nil do
|
||||
def.used = true
|
||||
|
||||
local epos = bpos + string.len(name)
|
||||
|
||||
-- The characters surrounding the name must be delimiters of beginning/end of string
|
||||
if (bpos == 1 or string.match(string.sub(source, bpos-1, bpos-1), "[%s(),=]")) and (epos > string.len(source) or string.match(string.sub(source, epos, epos), "[%s(),=]")) then
|
||||
new_source = ""
|
||||
|
||||
if bpos > 1 then
|
||||
new_source = new_source..string.sub(source, 1, bpos-1)
|
||||
end
|
||||
|
||||
sub = table.concat(def.items, ", ")
|
||||
|
||||
new_source = new_source..sub
|
||||
|
||||
if epos <= string.len(source) then
|
||||
new_source = new_source..string.sub(source, epos, string.len(source))
|
||||
end
|
||||
|
||||
source = new_source
|
||||
bpos = bpos + (string.len(sub)-string.len(name))
|
||||
end
|
||||
|
||||
bpos = string.find(source, name, bpos+1, true)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -176,7 +201,7 @@ function compiler.compile_macro(line, macro_defs, list_defs)
|
||||
|
||||
if (error_msg) then
|
||||
msg = "Compilation error when compiling \""..line.."\": ".. error_msg
|
||||
error(msg)
|
||||
return false, msg
|
||||
end
|
||||
|
||||
-- Simply as a validation step, try to expand all macros in this
|
||||
@@ -187,14 +212,18 @@ function compiler.compile_macro(line, macro_defs, list_defs)
|
||||
if (ast.type == "Rule") then
|
||||
-- Line is a filter, so expand macro references
|
||||
repeat
|
||||
expanded = expand_macros(ast_copy, macro_defs, false)
|
||||
status, expanded = expand_macros(ast_copy, macro_defs, false)
|
||||
if status == false then
|
||||
msg = "Compilation error when compiling \""..line.."\": ".. expanded
|
||||
return false, msg
|
||||
end
|
||||
until expanded == false
|
||||
|
||||
else
|
||||
error("Unexpected top-level AST type: "..ast.type)
|
||||
return false, "Unexpected top-level AST type: "..ast.type
|
||||
end
|
||||
|
||||
return ast
|
||||
return true, ast
|
||||
end
|
||||
|
||||
--[[
|
||||
@@ -208,22 +237,25 @@ function compiler.compile_filter(name, source, macro_defs, list_defs)
|
||||
|
||||
if (error_msg) then
|
||||
msg = "Compilation error when compiling \""..source.."\": "..error_msg
|
||||
error(msg)
|
||||
return false, msg
|
||||
end
|
||||
|
||||
if (ast.type == "Rule") then
|
||||
-- Line is a filter, so expand macro references
|
||||
repeat
|
||||
expanded = expand_macros(ast, macro_defs, false)
|
||||
status, expanded = expand_macros(ast, macro_defs, false)
|
||||
if status == false then
|
||||
return false, expanded
|
||||
end
|
||||
until expanded == false
|
||||
|
||||
else
|
||||
error("Unexpected top-level AST type: "..ast.type)
|
||||
return false, "Unexpected top-level AST type: "..ast.type
|
||||
end
|
||||
|
||||
filters = get_filters(ast)
|
||||
|
||||
return ast, filters
|
||||
return true, ast, filters
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -152,22 +152,6 @@ local function rel (left, sep, right)
|
||||
return left * sep * right / function(e1, op, e2) return { type = "BinaryRelOp", operator = op, left = e1, right = e2 } end
|
||||
end
|
||||
|
||||
local function fix_str (str)
|
||||
str = string.gsub(str, "\\a", "\a")
|
||||
str = string.gsub(str, "\\b", "\b")
|
||||
str = string.gsub(str, "\\f", "\f")
|
||||
str = string.gsub(str, "\\n", "\n")
|
||||
str = string.gsub(str, "\\r", "\r")
|
||||
str = string.gsub(str, "\\t", "\t")
|
||||
str = string.gsub(str, "\\v", "\v")
|
||||
str = string.gsub(str, "\\\n", "\n")
|
||||
str = string.gsub(str, "\\\r", "\n")
|
||||
str = string.gsub(str, "\\'", "'")
|
||||
str = string.gsub(str, '\\"', '"')
|
||||
str = string.gsub(str, '\\\\', '\\')
|
||||
return str
|
||||
end
|
||||
|
||||
-- grammar
|
||||
|
||||
|
||||
@@ -243,7 +227,7 @@ local G = {
|
||||
(digit^1 * V"Expo");
|
||||
Number = C(V"Hex" + V"Float" + V"Int") /
|
||||
function (n) return tonumber(n) end;
|
||||
String = (P'"' * C(((P'\\' * P(1)) + (P(1) - P'"'))^0) * P'"' + P"'" * C(((P"\\" * P(1)) + (P(1) - P"'"))^0) * P"'") / function (s) return fix_str(s) end;
|
||||
String = (P'"' * C(((P'\\' * P(1)) + (P(1) - P'"'))^0) * P'"' + P"'" * C(((P"\\" * P(1)) + (P(1) - P"'"))^0) * P"'");
|
||||
BareString = C(((P(1) - S' (),='))^1);
|
||||
|
||||
OrOp = kw("or") / "or";
|
||||
|
||||
@@ -59,17 +59,14 @@ function map(f, arr)
|
||||
return res
|
||||
end
|
||||
|
||||
priorities = {"Emergency", "Alert", "Critical", "Error", "Warning", "Notice", "Informational", "Debug"}
|
||||
|
||||
local function priority_num_for(s)
|
||||
s = string.lower(s)
|
||||
for i,v in ipairs(priorities) do
|
||||
if (string.find(string.lower(v), "^"..s)) then
|
||||
return i - 1 -- (numbers start at 0, lua indices start at 1)
|
||||
end
|
||||
end
|
||||
error("Invalid priority level: "..s)
|
||||
end
|
||||
-- Permissive for case and for common abbreviations.
|
||||
priorities = {
|
||||
Emergency=0, Alert=1, Critical=2, Error=3, Warning=4, Notice=5, Informational=5, Debug=7,
|
||||
emergency=0, alert=1, critical=2, error=3, warning=4, notice=5, informational=5, debug=7,
|
||||
EMERGENCY=0, ALERT=1, CRITICAL=2, ERROR=3, WARNING=4, NOTICE=5, INFORMATIONAL=5, DEBUG=7,
|
||||
INFO=5, info=5
|
||||
}
|
||||
|
||||
--[[
|
||||
Take a filter AST and set it up in the libsinsp runtime, using the filter API.
|
||||
@@ -183,47 +180,126 @@ function table.tostring( tbl )
|
||||
return "{" .. table.concat( result, "," ) .. "}"
|
||||
end
|
||||
|
||||
-- Split rules_content by lines and also remember the line numbers for
|
||||
-- each top -level object. Returns a table of lines and a table of
|
||||
-- line numbers for objects.
|
||||
|
||||
function load_rules(sinsp_lua_parser,
|
||||
json_lua_parser,
|
||||
rules_content,
|
||||
rules_mgr,
|
||||
verbose,
|
||||
all_events,
|
||||
extra,
|
||||
replace_container_info,
|
||||
min_priority)
|
||||
function split_lines(rules_content)
|
||||
lines = {}
|
||||
indices = {}
|
||||
|
||||
local rules = yaml.load(rules_content)
|
||||
local required_engine_version = 0
|
||||
idx = 1
|
||||
last_pos = 1
|
||||
pos = string.find(rules_content, "\n", 1, true)
|
||||
|
||||
if rules == nil then
|
||||
-- An empty rules file is acceptable
|
||||
return required_engine_version
|
||||
while pos ~= nil do
|
||||
line = string.sub(rules_content, last_pos, pos-1)
|
||||
if line ~= "" then
|
||||
lines[#lines+1] = line
|
||||
if string.len(line) >= 3 and string.sub(line, 1, 3) == "---" then
|
||||
-- Document marker, skip
|
||||
elseif string.sub(line, 1, 1) == '-' then
|
||||
indices[#indices+1] = idx
|
||||
end
|
||||
|
||||
idx = idx + 1
|
||||
end
|
||||
|
||||
last_pos = pos+1
|
||||
pos = string.find(rules_content, "\n", pos+1, true)
|
||||
end
|
||||
|
||||
if type(rules) ~= "table" then
|
||||
error("Rules content \""..rules_content.."\" is not yaml")
|
||||
if last_pos < string.len(rules_content) then
|
||||
line = string.sub(rules_content, last_pos)
|
||||
lines[#lines+1] = line
|
||||
if string.sub(line, 1, 1) == '-' then
|
||||
indices[#indices+1] = idx
|
||||
end
|
||||
|
||||
idx = idx + 1
|
||||
end
|
||||
|
||||
-- Add a final index for last line in document
|
||||
indices[#indices+1] = idx
|
||||
|
||||
return lines, indices
|
||||
end
|
||||
|
||||
function get_orig_yaml_obj(rules_lines, row)
|
||||
local ret = ""
|
||||
|
||||
idx = row
|
||||
while (idx <= #rules_lines) do
|
||||
ret = ret..rules_lines[idx].."\n"
|
||||
idx = idx + 1
|
||||
|
||||
if idx > #rules_lines or rules_lines[idx] == "" or string.sub(rules_lines[idx], 1, 1) == '-' then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
function get_lines(rules_lines, row, num_lines)
|
||||
local ret = ""
|
||||
|
||||
idx = row
|
||||
while (idx < (row + num_lines) and idx <= #rules_lines) do
|
||||
ret = ret..rules_lines[idx].."\n"
|
||||
idx = idx + 1
|
||||
end
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
function build_error(rules_lines, row, num_lines, err)
|
||||
local ret = err.."\n---\n"..get_lines(rules_lines, row, num_lines).."---"
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
function build_error_with_context(ctx, err)
|
||||
local ret = err.."\n---\n"..ctx.."---"
|
||||
return ret
|
||||
end
|
||||
|
||||
function load_rules_doc(rules_mgr, doc, load_state)
|
||||
|
||||
-- Iterate over yaml list. In this pass, all we're doing is
|
||||
-- populating the set of rules, macros, and lists. We're not
|
||||
-- expanding/compiling anything yet. All that will happen in a
|
||||
-- second pass
|
||||
for i,v in ipairs(rules) do
|
||||
for i,v in ipairs(doc) do
|
||||
|
||||
load_state.cur_item_idx = load_state.cur_item_idx + 1
|
||||
|
||||
-- Save back the original object as it appeared in the file. Will be used to provide context.
|
||||
local context = get_orig_yaml_obj(load_state.lines,
|
||||
load_state.indices[load_state.cur_item_idx])
|
||||
|
||||
if (not (type(v) == "table")) then
|
||||
error ("Unexpected element of type " ..type(v)..". Each element should be a yaml associative array.")
|
||||
return false, build_error_with_context(context, "Unexpected element of type " ..type(v)..". Each element should be a yaml associative array.")
|
||||
end
|
||||
|
||||
v['context'] = context
|
||||
|
||||
if (v['required_engine_version']) then
|
||||
required_engine_version = v['required_engine_version']
|
||||
load_state.required_engine_version = v['required_engine_version']
|
||||
if type(load_state.required_engine_version) ~= "number" then
|
||||
return false, build_error_with_context(v['context'], "Value of required_engine_version must be a number")
|
||||
end
|
||||
|
||||
if falco_rules.engine_version(rules_mgr) < v['required_engine_version'] then
|
||||
error("Rules require engine version "..v['required_engine_version']..", but engine version is "..falco_rules.engine_version(rules_mgr))
|
||||
return false, build_error_with_context(v['context'], "Rules require engine version "..v['required_engine_version']..", but engine version is "..falco_rules.engine_version(rules_mgr))
|
||||
end
|
||||
|
||||
elseif (v['macro']) then
|
||||
|
||||
if (v['macro'] == nil or type(v['macro']) == "table") then
|
||||
return false, build_error_with_context(v['context'], "Macro name is empty")
|
||||
end
|
||||
|
||||
if v['source'] == nil then
|
||||
v['source'] = "syscall"
|
||||
end
|
||||
@@ -232,9 +308,9 @@ function load_rules(sinsp_lua_parser,
|
||||
state.ordered_macro_names[#state.ordered_macro_names+1] = v['macro']
|
||||
end
|
||||
|
||||
for i, field in ipairs({'condition'}) do
|
||||
for j, field in ipairs({'condition'}) do
|
||||
if (v[field] == nil) then
|
||||
error ("Missing "..field.." in macro with name "..v['macro'])
|
||||
return false, build_error_with_context(v['context'], "Macro must have property "..field)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -247,24 +323,31 @@ function load_rules(sinsp_lua_parser,
|
||||
|
||||
if append then
|
||||
if state.macros_by_name[v['macro']] == nil then
|
||||
error ("Macro " ..v['macro'].. " has 'append' key but no macro by that name already exists")
|
||||
return false, build_error_with_context(v['context'], "Macro " ..v['macro'].. " has 'append' key but no macro by that name already exists")
|
||||
end
|
||||
|
||||
state.macros_by_name[v['macro']]['condition'] = state.macros_by_name[v['macro']]['condition'] .. " " .. v['condition']
|
||||
|
||||
-- Add the current object to the context of the base macro
|
||||
state.macros_by_name[v['macro']]['context'] = state.macros_by_name[v['macro']]['context'].."\n"..v['context']
|
||||
|
||||
else
|
||||
state.macros_by_name[v['macro']] = v
|
||||
end
|
||||
|
||||
elseif (v['list']) then
|
||||
|
||||
if (v['list'] == nil or type(v['list']) == "table") then
|
||||
return false, build_error_with_context(v['context'], "List name is empty")
|
||||
end
|
||||
|
||||
if state.lists_by_name[v['list']] == nil then
|
||||
state.ordered_list_names[#state.ordered_list_names+1] = v['list']
|
||||
end
|
||||
|
||||
for i, field in ipairs({'items'}) do
|
||||
for j, field in ipairs({'items'}) do
|
||||
if (v[field] == nil) then
|
||||
error ("Missing "..field.." in list with name "..v['list'])
|
||||
return false, build_error_with_context(v['context'], "List must have property "..field)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -277,10 +360,10 @@ function load_rules(sinsp_lua_parser,
|
||||
|
||||
if append then
|
||||
if state.lists_by_name[v['list']] == nil then
|
||||
error ("List " ..v['list'].. " has 'append' key but no list by that name already exists")
|
||||
return false, build_error_with_context(v['context'], "List " ..v['list'].. " has 'append' key but no list by that name already exists")
|
||||
end
|
||||
|
||||
for i, elem in ipairs(v['items']) do
|
||||
for j, elem in ipairs(v['items']) do
|
||||
table.insert(state.lists_by_name[v['list']]['items'], elem)
|
||||
end
|
||||
else
|
||||
@@ -290,7 +373,7 @@ function load_rules(sinsp_lua_parser,
|
||||
elseif (v['rule']) then
|
||||
|
||||
if (v['rule'] == nil or type(v['rule']) == "table") then
|
||||
error ("Missing name in rule")
|
||||
return false, build_error_with_context(v['context'], "Rule name is empty")
|
||||
end
|
||||
|
||||
-- By default, if a rule's condition refers to an unknown
|
||||
@@ -313,32 +396,39 @@ function load_rules(sinsp_lua_parser,
|
||||
if append then
|
||||
|
||||
-- For append rules, all you need is the condition
|
||||
for i, field in ipairs({'condition'}) do
|
||||
for j, field in ipairs({'condition'}) do
|
||||
if (v[field] == nil) then
|
||||
error ("Missing "..field.." in rule with name "..v['rule'])
|
||||
return false, build_error_with_context(v['context'], "Rule must have property "..field)
|
||||
end
|
||||
end
|
||||
|
||||
if state.rules_by_name[v['rule']] == nil then
|
||||
if state.skipped_rules_by_name[v['rule']] == nil then
|
||||
error ("Rule " ..v['rule'].. " has 'append' key but no rule by that name already exists")
|
||||
return false, build_error_with_context(v['context'], "Rule " ..v['rule'].. " has 'append' key but no rule by that name already exists")
|
||||
end
|
||||
else
|
||||
state.rules_by_name[v['rule']]['condition'] = state.rules_by_name[v['rule']]['condition'] .. " " .. v['condition']
|
||||
|
||||
-- Add the current object to the context of the base rule
|
||||
state.rules_by_name[v['rule']]['context'] = state.rules_by_name[v['rule']]['context'].."\n"..v['context']
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
for i, field in ipairs({'condition', 'output', 'desc', 'priority'}) do
|
||||
for j, field in ipairs({'condition', 'output', 'desc', 'priority'}) do
|
||||
if (v[field] == nil) then
|
||||
error ("Missing "..field.." in rule with name "..v['rule'])
|
||||
return false, build_error_with_context(v['context'], "Rule must have property "..field)
|
||||
end
|
||||
end
|
||||
|
||||
-- Convert the priority-as-string to a priority-as-number now
|
||||
v['priority_num'] = priority_num_for(v['priority'])
|
||||
v['priority_num'] = priorities[v['priority']]
|
||||
|
||||
if v['priority_num'] <= min_priority then
|
||||
if v['priority_num'] == nil then
|
||||
error("Invalid priority level: "..v['priority'])
|
||||
end
|
||||
|
||||
if v['priority_num'] <= load_state.min_priority then
|
||||
-- Note that we can overwrite rules, but the rules are still
|
||||
-- loaded in the order in which they first appeared,
|
||||
-- potentially across multiple files.
|
||||
@@ -356,11 +446,81 @@ function load_rules(sinsp_lua_parser,
|
||||
end
|
||||
end
|
||||
else
|
||||
error ("Unknown rule object: "..table.tostring(v))
|
||||
-- Remove the context from the table, so the table is exactly what was parsed
|
||||
local context = v['context']
|
||||
v['context'] = nil
|
||||
return false, build_error_with_context(context, "Unknown rule object: "..table.tostring(v))
|
||||
end
|
||||
end
|
||||
|
||||
-- We've now loaded all the rules, macros, and list. Now
|
||||
return true, ""
|
||||
end
|
||||
|
||||
function load_rules(sinsp_lua_parser,
|
||||
json_lua_parser,
|
||||
rules_content,
|
||||
rules_mgr,
|
||||
verbose,
|
||||
all_events,
|
||||
extra,
|
||||
replace_container_info,
|
||||
min_priority)
|
||||
|
||||
local load_state = {lines={}, indices={}, cur_item_idx=0, min_priority=min_priority, required_engine_version=0}
|
||||
|
||||
load_state.lines, load_state.indices = split_lines(rules_content)
|
||||
|
||||
local status, docs = pcall(yaml.load, rules_content, { all = true })
|
||||
|
||||
if status == false then
|
||||
local pat = "^([%d]+):([%d]+): "
|
||||
-- docs is actually an error string
|
||||
|
||||
local row = 0
|
||||
local col = 0
|
||||
|
||||
row, col = string.match(docs, pat)
|
||||
if row ~= nil and col ~= nil then
|
||||
docs = string.gsub(docs, pat, "")
|
||||
end
|
||||
|
||||
row = tonumber(row)
|
||||
col = tonumber(col)
|
||||
|
||||
return false, build_error(load_state.lines, row, 3, docs)
|
||||
end
|
||||
|
||||
if docs == nil then
|
||||
-- An empty rules file is acceptable
|
||||
return true, load_state.required_engine_version
|
||||
end
|
||||
|
||||
if type(docs) ~= "table" then
|
||||
return false, build_error(load_state.lines, 1, 1, "Rules content is not yaml")
|
||||
end
|
||||
|
||||
for docidx, doc in ipairs(docs) do
|
||||
|
||||
if type(doc) ~= "table" then
|
||||
return false, build_error(load_state.lines, 1, 1, "Rules content is not yaml")
|
||||
end
|
||||
|
||||
-- Look for non-numeric indices--implies that document is not array
|
||||
-- of objects.
|
||||
for key, val in pairs(doc) do
|
||||
if type(key) ~= "number" then
|
||||
return false, build_error(load_state.lines, 1, 1, "Rules content is not yaml array of objects")
|
||||
end
|
||||
end
|
||||
|
||||
res, errstr = load_rules_doc(rules_mgr, doc, load_state)
|
||||
|
||||
if not res then
|
||||
return res, errstr
|
||||
end
|
||||
end
|
||||
|
||||
-- We've now loaded all the rules, macros, and lists. Now
|
||||
-- compile/expand the rules, macros, and lists. We use
|
||||
-- ordered_rule_{lists,macros,names} to compile them in the order
|
||||
-- in which they appeared in the file(s).
|
||||
@@ -389,11 +549,15 @@ function load_rules(sinsp_lua_parser,
|
||||
state.lists[v['list']] = {["items"] = items, ["used"] = false}
|
||||
end
|
||||
|
||||
for i, name in ipairs(state.ordered_macro_names) do
|
||||
for _, name in ipairs(state.ordered_macro_names) do
|
||||
|
||||
local v = state.macros_by_name[name]
|
||||
|
||||
local ast = compiler.compile_macro(v['condition'], state.macros, state.lists)
|
||||
local status, ast = compiler.compile_macro(v['condition'], state.macros, state.lists)
|
||||
|
||||
if status == false then
|
||||
return false, build_error_with_context(v['context'], ast)
|
||||
end
|
||||
|
||||
if v['source'] == "syscall" then
|
||||
if not all_events then
|
||||
@@ -404,7 +568,7 @@ function load_rules(sinsp_lua_parser,
|
||||
state.macros[v['macro']] = {["ast"] = ast.filter.value, ["used"] = false}
|
||||
end
|
||||
|
||||
for i, name in ipairs(state.ordered_rule_names) do
|
||||
for _, name in ipairs(state.ordered_rule_names) do
|
||||
|
||||
local v = state.rules_by_name[name]
|
||||
|
||||
@@ -413,8 +577,12 @@ function load_rules(sinsp_lua_parser,
|
||||
warn_evttypes = v['warn_evttypes']
|
||||
end
|
||||
|
||||
local filter_ast, filters = compiler.compile_filter(v['rule'], v['condition'],
|
||||
state.macros, state.lists)
|
||||
local status, filter_ast, filters = compiler.compile_filter(v['rule'], v['condition'],
|
||||
state.macros, state.lists)
|
||||
|
||||
if status == false then
|
||||
return false, build_error_with_context(v['context'], filter_ast)
|
||||
end
|
||||
|
||||
local evtttypes = {}
|
||||
local syscallnums = {}
|
||||
@@ -433,10 +601,32 @@ function load_rules(sinsp_lua_parser,
|
||||
for filter, _ in pairs(filters) do
|
||||
found = false
|
||||
|
||||
for pat, _ in pairs(defined_filters) do
|
||||
if string.match(filter, pat) ~= nil then
|
||||
found = true
|
||||
break
|
||||
if defined_noarg_filters[filter] ~= nil then
|
||||
found = true
|
||||
else
|
||||
bracket_idx = string.find(filter, "[", 1, true)
|
||||
|
||||
if bracket_idx ~= nil then
|
||||
subfilter = string.sub(filter, 1, bracket_idx-1)
|
||||
|
||||
if defined_arg_filters[subfilter] ~= nil then
|
||||
found = true
|
||||
end
|
||||
end
|
||||
|
||||
if not found then
|
||||
dot_idx = string.find(filter, ".", 1, true)
|
||||
|
||||
while dot_idx ~= nil do
|
||||
subfilter = string.sub(filter, 1, dot_idx-1)
|
||||
|
||||
if defined_arg_filters[subfilter] ~= nil then
|
||||
found = true
|
||||
break
|
||||
end
|
||||
|
||||
dot_idx = string.find(filter, ".", dot_idx+1, true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -529,7 +719,7 @@ function load_rules(sinsp_lua_parser,
|
||||
formatter = formats.formatter(v['source'], v['output'])
|
||||
formats.free_formatter(v['source'], formatter)
|
||||
else
|
||||
error ("Unexpected type in load_rule: "..filter_ast.type)
|
||||
return false, build_error_with_context(v['context'], "Unexpected type in load_rule: "..filter_ast.type)
|
||||
end
|
||||
|
||||
::next_rule::
|
||||
@@ -552,7 +742,7 @@ function load_rules(sinsp_lua_parser,
|
||||
|
||||
io.flush()
|
||||
|
||||
return required_engine_version
|
||||
return true, load_state.required_engine_version
|
||||
end
|
||||
|
||||
local rule_fmt = "%-50s %s"
|
||||
|
||||
@@ -323,12 +323,12 @@ void falco_rules::load_rules(const string &rules_content,
|
||||
|
||||
lua_setglobal(m_ls, m_lua_ignored_syscalls.c_str());
|
||||
|
||||
// Create a table containing all filtercheck names.
|
||||
lua_newtable(m_ls);
|
||||
|
||||
vector<const filter_check_info*> fc_plugins;
|
||||
sinsp::get_filtercheck_fields_info(&fc_plugins);
|
||||
|
||||
set<string> no_argument_filters;
|
||||
set<string> argument_filters;
|
||||
|
||||
for(uint32_t j = 0; j < fc_plugins.size(); j++)
|
||||
{
|
||||
const filter_check_info* fci = fc_plugins[j];
|
||||
@@ -350,45 +350,71 @@ void falco_rules::load_rules(const string &rules_content,
|
||||
|
||||
// Some filters can work with or without an argument
|
||||
std::set<string> flexible_filters = {
|
||||
"^proc.aname",
|
||||
"^proc.apid"
|
||||
"proc.aname",
|
||||
"proc.apid"
|
||||
};
|
||||
|
||||
std::list<string> fields;
|
||||
std::string field_base = string("^") + fld->m_name;
|
||||
|
||||
if(fld->m_flags & EPF_REQUIRES_ARGUMENT ||
|
||||
flexible_filters.find(field_base) != flexible_filters.end())
|
||||
flexible_filters.find(fld->m_name) != flexible_filters.end())
|
||||
{
|
||||
fields.push_back(field_base + "[%[%.]");
|
||||
argument_filters.insert(fld->m_name);
|
||||
}
|
||||
|
||||
if(!(fld->m_flags & EPF_REQUIRES_ARGUMENT) ||
|
||||
flexible_filters.find(field_base) != flexible_filters.end())
|
||||
flexible_filters.find(fld->m_name) != flexible_filters.end())
|
||||
{
|
||||
fields.push_back(field_base + "$");
|
||||
}
|
||||
|
||||
for(auto &field : fields)
|
||||
{
|
||||
lua_pushstring(m_ls, field.c_str());
|
||||
lua_pushnumber(m_ls, 1);
|
||||
lua_settable(m_ls, -3);
|
||||
no_argument_filters.insert(fld->m_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(auto &chk_field : m_engine->json_factory().get_fields())
|
||||
{
|
||||
for(auto &field : chk_field.fields)
|
||||
for(auto &field : chk_field.m_fields)
|
||||
{
|
||||
lua_pushstring(m_ls, field.name.c_str());
|
||||
lua_pushnumber(m_ls, 1);
|
||||
lua_settable(m_ls, -3);
|
||||
switch(field.m_idx_mode)
|
||||
{
|
||||
case json_event_filter_check::IDX_REQUIRED:
|
||||
argument_filters.insert(field.m_name);
|
||||
break;
|
||||
case json_event_filter_check::IDX_ALLOWED:
|
||||
argument_filters.insert(field.m_name);
|
||||
no_argument_filters.insert(field.m_name);
|
||||
break;
|
||||
case json_event_filter_check::IDX_NONE:
|
||||
no_argument_filters.insert(field.m_name);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lua_setglobal(m_ls, m_lua_defined_filters.c_str());
|
||||
// Create tables containing all filtercheck
|
||||
// names. They are split into names that require
|
||||
// arguments and ones that do not.
|
||||
|
||||
lua_newtable(m_ls);
|
||||
|
||||
for(auto &field : argument_filters)
|
||||
{
|
||||
lua_pushstring(m_ls, field.c_str());
|
||||
lua_pushnumber(m_ls, 1);
|
||||
lua_settable(m_ls, -3);
|
||||
}
|
||||
|
||||
lua_setglobal(m_ls, m_lua_defined_arg_filters.c_str());
|
||||
|
||||
lua_newtable(m_ls);
|
||||
|
||||
for(auto &field : no_argument_filters)
|
||||
{
|
||||
lua_pushstring(m_ls, field.c_str());
|
||||
lua_pushnumber(m_ls, 1);
|
||||
lua_settable(m_ls, -3);
|
||||
}
|
||||
|
||||
lua_setglobal(m_ls, m_lua_defined_noarg_filters.c_str());
|
||||
|
||||
lua_pushlightuserdata(m_ls, m_sinsp_lua_parser);
|
||||
lua_pushlightuserdata(m_ls, m_json_lua_parser);
|
||||
@@ -399,15 +425,30 @@ void falco_rules::load_rules(const string &rules_content,
|
||||
lua_pushstring(m_ls, extra.c_str());
|
||||
lua_pushboolean(m_ls, (replace_container_info ? 1 : 0));
|
||||
lua_pushnumber(m_ls, min_priority);
|
||||
if(lua_pcall(m_ls, 9, 1, 0) != 0)
|
||||
if(lua_pcall(m_ls, 9, 2, 0) != 0)
|
||||
{
|
||||
const char* lerr = lua_tostring(m_ls, -1);
|
||||
|
||||
string err = "Error loading rules: " + string(lerr);
|
||||
|
||||
throw falco_exception(err);
|
||||
}
|
||||
|
||||
required_engine_version = lua_tonumber(m_ls, -1);
|
||||
lua_pop(m_ls, 1);
|
||||
// Either returns (true, required_engine_version), or (false, error string)
|
||||
bool successful = lua_toboolean(m_ls, -2);
|
||||
|
||||
if(successful)
|
||||
{
|
||||
required_engine_version = lua_tonumber(m_ls, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string err = lua_tostring(m_ls, -1);
|
||||
throw falco_exception(err);
|
||||
}
|
||||
|
||||
lua_pop(m_ls, 4);
|
||||
|
||||
} else {
|
||||
throw falco_exception("No function " + m_lua_load_rules + " found in lua rule module");
|
||||
}
|
||||
|
||||
@@ -67,7 +67,8 @@ class falco_rules
|
||||
string m_lua_load_rules = "load_rules";
|
||||
string m_lua_ignored_syscalls = "ignored_syscalls";
|
||||
string m_lua_ignored_events = "ignored_events";
|
||||
string m_lua_defined_filters = "defined_filters";
|
||||
string m_lua_defined_arg_filters = "defined_arg_filters";
|
||||
string m_lua_defined_noarg_filters = "defined_noarg_filters";
|
||||
string m_lua_events = "events";
|
||||
string m_lua_syscalls = "syscalls";
|
||||
string m_lua_describe_rule = "describe_rule";
|
||||
|
||||
@@ -202,19 +202,8 @@ void falco_ruleset::add(string &name,
|
||||
}
|
||||
}
|
||||
|
||||
void falco_ruleset::enable(const string &pattern, bool enabled, uint16_t ruleset)
|
||||
void falco_ruleset::enable(const string &substring, bool enabled, uint16_t ruleset)
|
||||
{
|
||||
regex re;
|
||||
bool match_using_regex = true;
|
||||
|
||||
try {
|
||||
re.assign(pattern);
|
||||
}
|
||||
catch (std::regex_error e)
|
||||
{
|
||||
match_using_regex = false;
|
||||
}
|
||||
|
||||
while (m_rulesets.size() < (size_t) ruleset + 1)
|
||||
{
|
||||
m_rulesets.push_back(new ruleset_filters());
|
||||
@@ -223,14 +212,9 @@ void falco_ruleset::enable(const string &pattern, bool enabled, uint16_t ruleset
|
||||
for(const auto &val : m_filters)
|
||||
{
|
||||
bool matches;
|
||||
if(match_using_regex)
|
||||
{
|
||||
matches = regex_match(val.first, re);
|
||||
}
|
||||
else
|
||||
{
|
||||
matches = (val.first.find(pattern) != string::npos);
|
||||
}
|
||||
|
||||
matches = (substring == "" || (val.first.find(substring) != string::npos));
|
||||
|
||||
if (matches)
|
||||
{
|
||||
if(enabled)
|
||||
|
||||
@@ -24,7 +24,6 @@ limitations under the License.
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <regex>
|
||||
|
||||
#include "sinsp.h"
|
||||
#include "filter.h"
|
||||
@@ -48,9 +47,9 @@ public:
|
||||
// specifying unnecessarily large rulesets will result in
|
||||
// unnecessarily large vectors.
|
||||
|
||||
// Find those rules matching the provided pattern and set
|
||||
// Find those rules matching the provided substring and set
|
||||
// their enabled status to enabled.
|
||||
void enable(const std::string &pattern, bool enabled, uint16_t ruleset = 0);
|
||||
void enable(const std::string &substring, bool enabled, uint16_t ruleset = 0);
|
||||
|
||||
// Find those rules that have a tag in the set of tags and set
|
||||
// their enabled status to enabled. Note that the enabled
|
||||
|
||||
@@ -18,13 +18,20 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "token_bucket.h"
|
||||
#include "utils.h"
|
||||
|
||||
token_bucket::token_bucket()
|
||||
token_bucket::token_bucket():
|
||||
token_bucket(sinsp_utils::get_current_time_ns)
|
||||
{
|
||||
}
|
||||
|
||||
token_bucket::token_bucket(std::function<uint64_t()> timer)
|
||||
{
|
||||
m_timer = timer;
|
||||
init(1, 1);
|
||||
}
|
||||
|
||||
@@ -37,20 +44,12 @@ void token_bucket::init(double rate, double max_tokens, uint64_t now)
|
||||
m_rate = rate;
|
||||
m_max_tokens = max_tokens;
|
||||
m_tokens = max_tokens;
|
||||
|
||||
if(now == 0)
|
||||
{
|
||||
now = sinsp_utils::get_current_time_ns();
|
||||
}
|
||||
|
||||
m_last_seen = now;
|
||||
m_last_seen = now == 0 ? m_timer() : now;
|
||||
}
|
||||
|
||||
bool token_bucket::claim()
|
||||
{
|
||||
uint64_t now = sinsp_utils::get_current_time_ns();
|
||||
|
||||
return claim(1, now);
|
||||
return claim(1, m_timer());
|
||||
}
|
||||
|
||||
bool token_bucket::claim(double tokens, uint64_t now)
|
||||
|
||||
@@ -20,6 +20,7 @@ limitations under the License.
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
|
||||
// A simple token bucket that accumulates tokens at a fixed rate and allows
|
||||
// for limited bursting in the form of "banked" tokens.
|
||||
@@ -27,6 +28,7 @@ class token_bucket
|
||||
{
|
||||
public:
|
||||
token_bucket();
|
||||
token_bucket(std::function<uint64_t()> timer);
|
||||
virtual ~token_bucket();
|
||||
|
||||
//
|
||||
@@ -52,6 +54,7 @@ public:
|
||||
uint64_t get_last_seen();
|
||||
|
||||
private:
|
||||
std::function<uint64_t()> m_timer;
|
||||
|
||||
//
|
||||
// The number of tokens generated per second.
|
||||
@@ -75,4 +78,3 @@ private:
|
||||
//
|
||||
uint64_t m_last_seen;
|
||||
};
|
||||
|
||||
|
||||
@@ -15,23 +15,11 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
include_directories("${PROJECT_SOURCE_DIR}/../sysdig/userspace/libsinsp/third-party/jsoncpp")
|
||||
include_directories("${LUAJIT_INCLUDE}")
|
||||
if(NOT SYSDIG_DIR)
|
||||
get_filename_component(SYSDIG_DIR "${PROJECT_SOURCE_DIR}/../sysdig" REALPATH)
|
||||
endif()
|
||||
|
||||
include_directories("${PROJECT_SOURCE_DIR}/../sysdig/userspace/libscap")
|
||||
include_directories("${PROJECT_SOURCE_DIR}/../sysdig/userspace/libsinsp")
|
||||
include_directories("${PROJECT_SOURCE_DIR}/../sysdig/userspace/sysdig")
|
||||
include_directories("${PROJECT_SOURCE_DIR}/userspace/engine")
|
||||
include_directories("${PROJECT_BINARY_DIR}/userspace/falco")
|
||||
include_directories("${PROJECT_BINARY_DIR}/driver/src")
|
||||
include_directories("${CURL_INCLUDE_DIR}")
|
||||
include_directories("${TBB_INCLUDE_DIR}")
|
||||
include_directories("${NJSON_INCLUDE}")
|
||||
include_directories("${YAMLCPP_INCLUDE_DIR}")
|
||||
include_directories("${CIVETWEB_INCLUDE_DIR}")
|
||||
include_directories("${DRAIOS_DEPENDENCIES_DIR}/yaml-${DRAIOS_YAML_VERSION}/target/include")
|
||||
|
||||
configure_file("${PROJECT_SOURCE_DIR}/../sysdig/userspace/sysdig/config_sysdig.h.in" config_sysdig.h)
|
||||
configure_file("${SYSDIG_DIR}/userspace/sysdig/config_sysdig.h.in" config_sysdig.h)
|
||||
|
||||
add_executable(falco
|
||||
configuration.cpp
|
||||
@@ -39,29 +27,35 @@ add_executable(falco
|
||||
falco_outputs.cpp
|
||||
event_drops.cpp
|
||||
statsfilewriter.cpp
|
||||
timer.cpp
|
||||
module_utils.cpp
|
||||
falco.cpp
|
||||
"${PROJECT_SOURCE_DIR}/../sysdig/userspace/sysdig/fields_info.cpp"
|
||||
"${SYSDIG_DIR}/userspace/sysdig/fields_info.cpp"
|
||||
webserver.cpp)
|
||||
|
||||
target_include_directories(falco PUBLIC
|
||||
"${SYSDIG_DIR}/userspace/sysdig"
|
||||
"${PROJECT_SOURCE_DIR}/userspace/engine"
|
||||
"${PROJECT_BINARY_DIR}/userspace/falco"
|
||||
"${PROJECT_BINARY_DIR}/driver/src"
|
||||
"${YAMLCPP_INCLUDE_DIR}"
|
||||
"${CIVETWEB_INCLUDE_DIR}"
|
||||
"${DRAIOS_DEPENDENCIES_DIR}/yaml-${DRAIOS_YAML_VERSION}/target/include")
|
||||
|
||||
target_link_libraries(falco falco_engine sinsp)
|
||||
target_link_libraries(falco
|
||||
"${LIBYAML_LIB}"
|
||||
"${LIBYAML_LIB}"
|
||||
"${YAMLCPP_LIB}"
|
||||
"${CIVETWEB_LIB}")
|
||||
|
||||
configure_file(config_falco.h.in config_falco.h)
|
||||
|
||||
add_custom_command(TARGET falco
|
||||
COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/verify_engine_fields.sh ${CMAKE_SOURCE_DIR}
|
||||
COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/verify_engine_fields ${CMAKE_SOURCE_DIR}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMENT "Comparing engine fields checksum in falco_engine.h to actual fields"
|
||||
)
|
||||
|
||||
# add_custom_target(verify_engine_fields
|
||||
# DEPENDS verify_engine_fields.sh falco_engine.h)
|
||||
|
||||
# add_dependencies(verify_engine_fields falco)
|
||||
|
||||
install(TARGETS falco DESTINATION ${FALCO_BIN_DIR})
|
||||
install(DIRECTORY lua
|
||||
DESTINATION ${FALCO_SHARE_DIR}
|
||||
|
||||
@@ -19,7 +19,7 @@ limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#define FALCO_VERSION "${FALCO_VERSION}"
|
||||
#define FALCO_VERSION "@FALCO_VERSION@"
|
||||
|
||||
#define FALCO_LUA_DIR "${CMAKE_INSTALL_PREFIX}/${FALCO_SHARE_DIR}/lua/"
|
||||
#define FALCO_SOURCE_DIR "${PROJECT_SOURCE_DIR}"
|
||||
@@ -27,4 +27,4 @@ limitations under the License.
|
||||
#define FALCO_INSTALL_CONF_FILE "/etc/falco/falco.yaml"
|
||||
#define FALCO_SOURCE_LUA_DIR "${PROJECT_SOURCE_DIR}/userspace/falco/lua/"
|
||||
|
||||
#define PROBE_NAME "${PROBE_NAME}"
|
||||
#define PROBE_NAME "@PROBE_NAME@"
|
||||
|
||||
@@ -220,6 +220,15 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
|
||||
m_syscall_evt_drop_rate = m_config->get_scalar<double>("syscall_event_drops", "rate", 0.3333);
|
||||
m_syscall_evt_drop_max_burst = m_config->get_scalar<double>("syscall_event_drops", "max_burst", 10);
|
||||
|
||||
m_module_check_frequency = m_config->get_scalar<uint64_t>("module_check", "frequency", 10);
|
||||
if(m_module_check_frequency < 10) {
|
||||
throw invalid_argument("Module check frequency must be higher than 10 seconds");
|
||||
}
|
||||
m_module_check_max_consecutive_failures = m_config->get_scalar<int>("module_check", "max_consecutive_failures", 3);
|
||||
m_module_check_backoff_max_attempts = m_config->get_scalar<int>("module_check", "backoff", "max_attempts", 5);
|
||||
m_module_check_backoff_init_delay = m_config->get_scalar<uint64_t>("module_check", "backoff", "init_delay", 100);
|
||||
m_module_check_backoff_max_delay = m_config->get_scalar<uint64_t>("module_check", "backoff", "max_delay", 3000);
|
||||
|
||||
m_syscall_evt_simulate_drops = m_config->get_scalar<bool>("syscall_event_drops", "simulate_drops", false);
|
||||
}
|
||||
|
||||
|
||||
@@ -133,6 +133,47 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a scalar value defined inside a 3 level nested structure like:
|
||||
* file_output:
|
||||
* enabled: true
|
||||
* filename: output_file.txt
|
||||
*
|
||||
* get_scalar<bool>("file_output", "enabled", false)
|
||||
*/
|
||||
template<typename T>
|
||||
const T get_scalar(const std::string& key, const std::string& subkey, const std::string& subsubkey, const T& default_value)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto node = m_root[key][subkey][subsubkey];
|
||||
if (node.IsDefined())
|
||||
{
|
||||
return node.as<T>();
|
||||
}
|
||||
}
|
||||
catch (const YAML::BadConversion& ex)
|
||||
{
|
||||
std::cerr << "Cannot read config file (" + m_path + "): wrong type at key " + key + "\n";
|
||||
throw;
|
||||
}
|
||||
|
||||
return default_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the second-level node identified by key[key][subkey] to value.
|
||||
*/
|
||||
template<typename T>
|
||||
void set_scalar(const std::string& key, const std::string& subkey, const std::string& subsubkey, const T& value)
|
||||
{
|
||||
auto node = m_root;
|
||||
if (node.IsDefined())
|
||||
{
|
||||
node[key][subkey][subsubkey] = value;
|
||||
}
|
||||
}
|
||||
|
||||
// called with the last variadic arg (where the sequence is expected to be found)
|
||||
template <typename T>
|
||||
void get_sequence_from_node(T& ret, const YAML::Node &node)
|
||||
@@ -216,6 +257,12 @@ class falco_configuration
|
||||
double m_syscall_evt_drop_rate;
|
||||
double m_syscall_evt_drop_max_burst;
|
||||
|
||||
uint64_t m_module_check_frequency;
|
||||
int m_module_check_max_consecutive_failures;
|
||||
int m_module_check_backoff_max_attempts;
|
||||
uint64_t m_module_check_backoff_init_delay;
|
||||
uint64_t m_module_check_backoff_max_delay;
|
||||
|
||||
// Only used for testing
|
||||
bool m_syscall_evt_simulate_drops;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user