Compare commits

...

109 Commits

Author SHA1 Message Date
Luca Guerra
37ce18f457 fix(docker): prevent variable expansion with FALCO_DRIVER_LOADER_OPTIONS
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-11 14:59:30 +02:00
Luca Guerra
dae36c798a new(docker): allow passing options to falco-driver-loader from the container image
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-11 14:59:30 +02:00
dependabot[bot]
30aa28f2a6 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `b6372d2` to `d31dbc2`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](b6372d2675...d31dbc26ea)

---
updated-dependencies:
- dependency-name: submodules/falcosecurity-rules
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-11 10:59:14 +02:00
Luca Guerra
d5e80fee0b update(docs): add section about the experimental distroless image
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-11 10:03:13 +02:00
Luca Guerra
b3b4f4a431 update(build): build and release falco-distroless
Signed-off-by: Luca Guerra <luca@guerra.sh>
Co-authored-by: Leonardo Grasso <me@leonardograsso.com>
2023-09-11 10:03:13 +02:00
Adrian Mouat
de5eec5285 new(docker): add distroless Dockerfile
Signed-off-by: Adrian Mouat <adrian@chainguard.dev>
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-11 10:03:13 +02:00
Leonardo Grasso
35cb960917 update(userspace/engine): align %container.info defaults with new rule styles
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-09-08 19:00:04 +02:00
Andrea Terzolo
e55bedac0b fix(stats): always initialize m_output
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-07 19:13:00 +02:00
Luca Guerra
c2b940f8c4 update(docker): remove packages that are not strictly necessary
Signed-off-by: Luca Guerra <luca@guerra.sh>
Co-authored-by: Leonardo Grasso <me@leonardograsso.com>
2023-09-07 15:55:59 +02:00
Luca Guerra
22bd6f7352 update(build): publish the legacy driver image
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-07 15:55:59 +02:00
Luca Guerra
1616ac666b update(docker): add the legacy driver loader image
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-07 15:55:59 +02:00
Luca Guerra
02982e0375 update(docker): upgrade Falco driver loader image
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-07 15:55:59 +02:00
dependabot[bot]
eb8e4b9a29 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `6ed73fe` to `b6372d2`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](6ed73fee78...b6372d2675)

---
updated-dependencies:
- dependency-name: submodules/falcosecurity-rules
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-07 13:41:59 +02:00
Melissa Kilby
73f15e6c5b cleanup(userspace/falco): adjust outputs_queue_num_drops counter for recovery 'empty'
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-09-07 13:15:59 +02:00
Melissa Kilby
dad2762ed6 fix(userspace/falco): change outputs_queue_num_drops to atomic
Co-authored-by: Jason Dellaluce <jasondellaluce@gmail.com>
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-09-07 13:15:59 +02:00
Melissa Kilby
88a5e1bf45 cleanup(config): rename default outputs queue macro
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-09-07 13:15:59 +02:00
Melissa Kilby
0eff98aa8e cleanup: apply more reviewers suggestions
Co-authored-by: Andrea Terzolo <andreaterzolo3@gmail.com>
Co-authored-by: Leonardo Grasso <me@leonardograsso.com>
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-09-07 13:15:59 +02:00
Melissa Kilby
016fdae93b cleanup: apply reviewers suggestions
Co-authored-by: Andrea Terzolo <andreaterzolo3@gmail.com>
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-09-07 13:15:59 +02:00
Melissa Kilby
a61f24066f cleanup(userspace/falco): always set queue capacity and use largest long as default for unbounded
Co-authored-by: Andrea Terzolo <andreaterzolo3@gmail.com>
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-09-07 13:15:59 +02:00
Melissa Kilby
1e94598eca new(metrics): add falco.outputs_queue_num_drops metrics + plus fix rebase leftovers
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-09-07 13:15:59 +02:00
Melissa Kilby
85883b7200 cleanup(outputs): adopt different style for outputs_queue params encodings
Co-authored-by: Leonardo Grasso <me@leonardograsso.com>
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-09-07 13:15:59 +02:00
Melissa Kilby
03a557725b cleanup(outputs): ensure old defaults in queue_capacity_outputs in new config
Co-authored-by: Leonardo Grasso <me@leonardograsso.com>
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-09-07 13:15:59 +02:00
Melissa Kilby
b55b209edf fix(outputs): expose queue_capacity_outputs config for memory control
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-09-07 13:15:59 +02:00
Luca Guerra
d1b932d2e9 update(docker): use debian 12 slim for falco no driver
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-07 12:49:59 +02:00
Luca Guerra
a22dac6866 update(falco)!: --list-syscall-events is now called --list-events
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-07 12:47:59 +02:00
Luca Guerra
bfb22527a2 chore(falco): update engine version and checksum
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-07 12:47:59 +02:00
Luca Guerra
b21bfd6e8d new(falco): print all events (not just syscall)
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-07 12:47:59 +02:00
Leonardo Grasso
79b39b54d0 update(cmake/modules): bump rules to falco-rules-2.0.0-rc1
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-09-07 12:34:59 +02:00
Leonardo Grasso
7cd299e658 chore(submodule): bump testing framework to 76d1743
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-09-07 12:34:59 +02:00
Leonardo Grasso
e8e8c6413f fix(ci): make scap file work from within the container
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-09-07 12:34:59 +02:00
Federico Di Pierro
4d590fa6ee update(cmake): bumped libs to 0.13.0-rc1 and driver to 6.0.0+driver.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-06 17:20:00 +02:00
Daniel Wright
513f122aff feat: support parsing of system environment variables in yaml
In order to allow the user to supply environment variables in standard
ways performed in other applications the get_scalar function has been
extended to support defining an environment variable in the format
`${FOO}`. Environment variables can be escaped via defining as `$${FOO}`.
As this handles some additional complexity, a unit test has been  added
to cover this new functionality

Signed-off-by: Daniel Wright <danielwright@bitgo.com>
2023-09-06 11:45:00 +02:00
dependabot[bot]
5ffffeeada build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `b42893a` to `6ed73fe`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](b42893a6eb...6ed73fee78)

---
updated-dependencies:
- dependency-name: submodules/falcosecurity-rules
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-06 09:59:59 +02:00
Vicente J. Jiménez Miras
3dae1cbf91 docs(README.md): correct URL
Signed-off-by: Vicente J. Jiménez Miras <vjjmiras@gmail.com>
2023-09-05 17:07:57 +02:00
Andrea Terzolo
12735bdfb1 chore: bump Falco to latest libs
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-05 16:41:57 +02:00
Andrea Terzolo
f7c628f623 ci: disable falco-driver-loader tests on ARM64
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-05 11:15:55 +02:00
Leonardo Grasso
b2374b3c19 fix(userspace/falco): apply suggestions for CLI help messages
Co-authored-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-09-04 18:50:52 +02:00
Leonardo Grasso
93e8be1e32 update(userspace/falco): revised CLI help messages
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-09-04 18:50:52 +02:00
Luca Guerra
b246bcb052 fix(engine): fix werror reorder
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-04 17:26:52 +02:00
Andrea Terzolo
6251af0ab6 new: introduce new stats updated to the latest libs version
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-04 17:24:52 +02:00
Andrea Terzolo
ce79e01ae8 ci: support tests on amazon-linux
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-04 15:12:51 +02:00
Leonardo Grasso
9db4c9b2cb build(cmake/modules): upgrade falcoctl to version 0.6.0
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-09-04 14:18:51 +02:00
Andrea Terzolo
dba685eeda tests: enable e2e falco-driver-loader tests
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-04 12:19:46 +02:00
Andrea Terzolo
4f8d11acdd chore: bump engine version and checksum
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-04 12:19:46 +02:00
Andrea Terzolo
3c47915c56 chore: bump Falco to latest libs master
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-04 12:19:46 +02:00
Federico Di Pierro
0ec492086e fix(userspace/falco): properly delete metrics timer upon leaving.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-04 11:22:46 +02:00
Andrea Terzolo
442d1accbe cleanup: deprecate rate limiter mechanism
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-04 10:11:45 +02:00
Melissa Kilby
79577237a1 cleanup(config): add info about performance impact wrt rule_matching
Co-authored-by: Andrea Terzolo <andreaterzolo3@gmail.com>
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-09-04 10:10:46 +02:00
Melissa Kilby
08237b946f cleanup(config): add more info
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-09-04 10:10:46 +02:00
Andrea Terzolo
62e762a467 cleanup: deprecate no more supported userspace mode
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-04 10:09:46 +02:00
Andrea Terzolo
e6fe0a516d fix: fix falco MINIMAL_BUILD
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-04 10:09:46 +02:00
dependabot[bot]
a6b12a5c97 build(deps): Bump submodules/falcosecurity-testing
Bumps [submodules/falcosecurity-testing](https://github.com/falcosecurity/testing) from `b39c807` to `9110022`.
- [Commits](b39c807a19...91100227b0)

---
updated-dependencies:
- dependency-name: submodules/falcosecurity-testing
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-04 10:08:46 +02:00
dependabot[bot]
b15a51a825 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `3f52480` to `b42893a`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](3f52480618...b42893a6eb)

---
updated-dependencies:
- dependency-name: submodules/falcosecurity-rules
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-01 06:50:31 +02:00
Jason Dellaluce
c8122ff474 fix(userspace/engine): support appending to unknown sources
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-09-01 06:46:31 +02:00
Jason Dellaluce
88dcdaac8a update(submodules): bump falcosecurity-testing to b39c807
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-08-31 18:33:30 +02:00
Jason Dellaluce
eabf49892d update(userspace/falco): bump engine version to 24
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-08-31 18:33:30 +02:00
Jason Dellaluce
901fca2257 update(userspace/engine): upgrade skip-if-unknown-filter YAML field
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-08-31 18:33:30 +02:00
Andrea Terzolo
cc8d6705f6 fix: fix "ebpf_enabled" output stat
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-08-31 17:37:29 +02:00
Federico Di Pierro
26f626c1d5 chore(userspace/falco): properly check that parent init() did not fail for reasons.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>

Co-authored-by: Leonardo Grasso <me@leonardograsso.com>
2023-08-31 16:11:29 +02:00
Federico Di Pierro
acaaa0b4ca cleanup(userspace/falco): improvements to the http output perf.
Moreover, add option to disable stdout echoing.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-08-31 16:11:29 +02:00
hjenkins
63ba15962b fix(scripts): falco-driver-loader add print env
Fixes #2352

Needed to refactor the target_id code paths to allow this to be used in
env printing and sourcing.

Signed-off-by: hjenkins <henry@henryjenkins.name>
2023-08-31 12:10:28 +02:00
dependabot[bot]
f163780d62 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `3ceea88` to `40a9817`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](3ceea88eeb...40a9817330)

---
updated-dependencies:
- dependency-name: submodules/falcosecurity-rules
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-31 09:22:29 +02:00
Jason Dellaluce
01093d2dfc fix(userspace/engine): support both old and new gcc + std::move
Old gcc versions (e.g. 4.8.3) won't allow move elision
but newer versions (e.g. 10.2.1) would complain about
the redundant move.

Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-08-30 20:57:27 +02:00
Jason Dellaluce
a6c2bf7123 update(cmake): support building libs and driver from forks
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-08-30 19:13:26 +02:00
Andrea Terzolo
988703b601 clenaup: remove b64 from falco dependencies
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-08-30 19:12:26 +02:00
jabdr
66841d8009 Support reload in falco-modern-bpf.service
Signed-off-by: jabdr <jd@q321.de>
2023-08-30 15:28:26 +02:00
jabdr
43ae8b0cac Support reload in falco-custom.service
Signed-off-by: jabdr <jd@q321.de>
2023-08-30 15:28:26 +02:00
jabdr
9a5f625d5f Support reload in falco-bpf.service
Signed-off-by: jabdr <jd@q321.de>
2023-08-30 15:28:26 +02:00
jabdr
799c09e638 Support reload in falco-kmod.service
Signed-off-by: jabdr <jd@q321.de>
2023-08-30 15:28:26 +02:00
Richard Tweed
2f267a044e Merge in master
Signed-off-by: Richard Tweed <RichardoC@users.noreply.github.com>
2023-08-29 17:57:21 +02:00
Richard Tweed
7b6d45c394 Update README. based on FedeDP's suggestion
Co-authored-by: Federico Di Pierro <nierro92@gmail.com>
Signed-off-by: Richard Tweed <RichardoC@users.noreply.github.com>
2023-08-29 17:57:21 +02:00
Richard Tweed
368796df61 Issue 2391 Document why Falco is written in C++ rather than anything else
Signed-off-by: Richard Tweed <RichardoC@users.noreply.github.com>
2023-08-29 17:57:21 +02:00
Andrea Terzolo
8d6c6900d3 cleanup: turn a warning into an error
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-08-29 13:46:21 +02:00
Andrea Terzolo
34d796439f cleanup: fail if the time unit is not specified
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-08-29 13:46:21 +02:00
Anna Simon
c8d1637130 feat(userspace/outputs_http): Add option for mTLS
Signed-off-by: Anna Simon <asimon@mercari.com>
2023-08-29 10:28:21 +02:00
Jason Dellaluce
600318aaae update(ci): minimize retention days for build-only CI artifacts
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-08-29 09:33:21 +02:00
Andrea Terzolo
ba1528e3c2 cleanup: remove unused --pidfile option
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-08-28 17:06:19 +02:00
Melissa Kilby
37ea9b25c4 feat(userspace): deprecate -d daemonize option
Deprecate `-d` option (currently broken).

Symptoms included the message queue filling up without popping any messages
even though events were handled normally.

Maintainers decided to deprecate not needed `-d` option while keeping
the useful `pidfile` command args option.

Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-08-25 18:14:45 +02:00
Melissa Kilby
b66bf2c6e4 cleanup: remove some unused variables
Co-authored-by: Andrea Terzolo <andreaterzolo3@gmail.com>
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-08-25 15:20:45 +02:00
Melissa Kilby
0d4e77bcbe cleanup(config): assign Stable to metrics config
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-08-25 15:20:45 +02:00
Melissa Kilby
6cdb740786 cleanup(userspace): update parse_prometheus_interval
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-08-25 15:20:45 +02:00
Melissa Kilby
9a12a93342 feat(userspace): deprecate stats command args option in favor of metrics configs in falco.yaml
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-08-25 15:20:45 +02:00
Leonardo Grasso
84fe33a029 fix(userspace/falco): correct typo in -p help message
Co-authored-by: Andrea Terzolo <andrea.terzolo@polito.it>
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-08-25 15:18:45 +02:00
Leonardo Grasso
8fbf49bbba update(userspace/falco): new defaults for -p presets
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-08-25 15:18:45 +02:00
Leonardo Grasso
f10d0499d2 update(userspace/falco): improve help message for -p option
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-08-25 15:18:45 +02:00
dependabot[bot]
259095651b build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `bf1639a` to `3ceea88`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](bf1639a574...3ceea88eeb)

---
updated-dependencies:
- dependency-name: submodules/falcosecurity-rules
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-25 10:26:45 +02:00
dependabot[bot]
e5b9dd2dfc build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `64ce419` to `bf1639a`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](64ce419d92...bf1639a574)

---
updated-dependencies:
- dependency-name: submodules/falcosecurity-rules
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-24 11:48:39 +02:00
Melissa Kilby
9620515e40 cleanup(config): assign Stable to base_syscalls config
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-08-24 10:41:39 +02:00
Jason Dellaluce
4f3181cb1c update(userspace/engine): bump engine version to 23
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-08-24 10:30:40 +02:00
Jason Dellaluce
fe66abf15c update(cmake): bump libs and driver to 6caaa3c85d7c783b29cd32832f2552a4bd6cd739
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-08-24 10:30:40 +02:00
Jason Dellaluce
527c42c030 chore: polish conditional compilation flags for emscripten
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-08-24 10:30:40 +02:00
Jason Dellaluce
aa62b65c70 update(cmake): bump libs and drivers to 1bb3eea5380c06a4aceb635f70cf62829951ef00
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-08-24 10:30:40 +02:00
Jason Dellaluce
78e2ddc63e fix: solve cmake issues
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-08-24 10:30:40 +02:00
Jason Dellaluce
179b191f70 chore(cmake): cleanup comment
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
Co-authored-by: Rohith Raju <rohithraju488@gmail.com>
2023-08-24 10:30:40 +02:00
Jason Dellaluce
a439d5b556 refactor(ci): build and upload WASM packages
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
Co-authored-by: Rohith Raju <rohithraju488@gmail.com>
2023-08-24 10:30:40 +02:00
Jason Dellaluce
828fa7d14d update(cmake): fix wasm package content
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
Co-authored-by: Rohith Raju <rohithraju488@gmail.com>
2023-08-24 10:30:40 +02:00
Jason Dellaluce
590b034a55 fix: solve plugin loading error
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
Co-authored-by: Rohith Raju <rohithraju488@gmail.com>
2023-08-24 10:30:40 +02:00
Jason Dellaluce
54ab1eed9e update(cmake): update add emmc link_options
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
Co-authored-by: Rohith Raju <rohithraju488@gmail.com>
2023-08-24 10:30:40 +02:00
rohith-raju
05f483d751 update(cleanup): clean gitignore file
Signed-off-by: rohith-raju <rohithraju488@gmail.com>
2023-08-24 10:30:40 +02:00
rohith-raju
c73e43c973 cleanup: fix workflow and build errors
Signed-off-by: rohith-raju <rohithraju488@gmail.com>
2023-08-24 10:30:40 +02:00
rohith-raju
e8ee850dee update(ci,cmake): add support for emscripten build
Signed-off-by: rohith-raju <rohithraju488@gmail.com>
2023-08-24 10:30:40 +02:00
rohith-raju
105f2f6ee3 update(unit_tests): use typecast as wasm can't handle 64 bit int
Signed-off-by: rohith-raju <rohithraju488@gmail.com>
2023-08-24 10:30:40 +02:00
Jason Dellaluce
ce6368a89e fix: solve runtime issues with emscripten build
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
Co-authored-by: Rohith Raju <rohithraju488@gmail.com>
2023-08-24 10:30:40 +02:00
Jason Dellaluce
0faa45669b update(build): setup cpack for emscripten build
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
Co-authored-by: Rohith Raju <rohithraju488@gmail.com>
2023-08-24 10:30:40 +02:00
Jason Dellaluce
aa6061681d update: adapt code to multi-platform builds
Co-authored-by: Rohith Raju <rohithraju488@gmail.com>
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-08-24 10:30:40 +02:00
Jason Dellaluce
86e76924a1 update: adapt cmake setup for non-linux and emscripten builds
Co-authored-by: Rohith Raju <rohithraju488@gmail.com>
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-08-24 10:30:40 +02:00
Johanan Liebermann
e7c5139563 Allow specifying kernel release and version
Signed-off-by: Johanan Liebermann <jliebermann@microsoft.com>
2023-08-24 09:17:39 +02:00
Andrea Terzolo
bc12e567e5 docs(config.yaml): fix wrong severity levels in sinsp
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-08-23 11:44:28 +02:00
dependabot[bot]
b2ad928d6c build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `0d0e333` to `64ce419`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](0d0e333151...64ce419d92)

---
updated-dependencies:
- dependency-name: submodules/falcosecurity-rules
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-23 10:20:27 +02:00
83 changed files with 1563 additions and 728 deletions

View File

@@ -56,7 +56,7 @@ jobs:
git_ref: ${{ github.event.pull_request.head.sha }}
minimal: false
build_type: Debug
cmd: "echo $(build/userspace/falco/falco -c ./falco.yaml --version | grep 'Engine:' | awk '{print $2}') $(echo $(build/userspace/falco/falco -c ./falco.yaml --version | grep 'Schema version:' | awk '{print $3}') $(build/userspace/falco/falco -c ./falco.yaml --list --markdown | grep '^`' | sort) $(build/userspace/falco/falco -c ./falco.yaml --list-syscall-events | sort) | sha256sum)"
cmd: "echo $(build/userspace/falco/falco -c ./falco.yaml --version | grep 'Engine:' | awk '{print $2}') $(echo $(build/userspace/falco/falco -c ./falco.yaml --version | grep 'Schema version:' | awk '{print $3}') $(build/userspace/falco/falco -c ./falco.yaml --list --markdown | grep '^`' | sort) $(build/userspace/falco/falco -c ./falco.yaml --list-events | sort) | sha256sum)"
# checks the falco engine checksum for consistency
check-engine-checksum:

View File

@@ -46,6 +46,16 @@ jobs:
--build-arg TARGETARCH=${TARGETARCH} \
.
docker save docker.io/falcosecurity/falco-no-driver:${{ inputs.arch }}-${{ inputs.tag }} --output /tmp/falco-no-driver-${{ inputs.arch }}.tar
- name: Build distroless image
run: |
cd ${{ github.workspace }}/docker/no-driver/
docker build -f Dockerfile.distroless -t docker.io/falcosecurity/falco-distroless:${{ inputs.arch }}-${{ inputs.tag }} \
--build-arg VERSION_BUCKET=bin${{ inputs.bucket_suffix }} \
--build-arg FALCO_VERSION=${{ inputs.version }} \
--build-arg TARGETARCH=${TARGETARCH} \
.
docker save docker.io/falcosecurity/falco-distroless:${{ inputs.arch }}-${{ inputs.tag }} --output /tmp/falco-distroless-${{ inputs.arch }}.tar
- name: Build falco image
run: |
@@ -65,9 +75,18 @@ jobs:
--build-arg TARGETARCH=${TARGETARCH} \
.
docker save docker.io/falcosecurity/falco-driver-loader:${{ inputs.arch }}-${{ inputs.tag }} --output /tmp/falco-driver-loader-${{ inputs.arch }}.tar
- name: Build falco-driver-loader-legacy image
run: |
cd ${{ github.workspace }}/docker/driver-loader/
docker build -t docker.io/falcosecurity/falco-driver-loader-legacy:${{ inputs.arch }}-${{ inputs.tag }} \
--build-arg TARGETARCH=${TARGETARCH} \
.
docker save docker.io/falcosecurity/falco-driver-loader-legacy:${{ inputs.arch }}-${{ inputs.tag }} --output /tmp/falco-driver-loader-legacy-${{ inputs.arch }}.tar
- name: Upload images tarballs
uses: actions/upload-artifact@v3
with:
name: falco-images
path: /tmp/falco-*.tar
retention-days: 1

View File

@@ -36,6 +36,7 @@ jobs:
with:
name: bpf_probe_${{ inputs.arch }}.skel.h
path: skeleton-build/skel_dir/bpf_probe.skel.h
retention-days: 1
build-packages:
# See https://github.com/actions/runner/issues/409#issuecomment-1158849936
@@ -158,3 +159,59 @@ jobs:
name: falco-${{ inputs.version }}-static-x86_64.tar.gz
path: |
${{ github.workspace }}/build/falco-${{ inputs.version }}-static-x86_64.tar.gz
build-wasm-package:
if: ${{ inputs.arch == 'x86_64' }}
runs-on: ubuntu-latest
steps:
# Always install deps before invoking checkout action, to properly perform a full clone.
- name: Install build dependencies
run: |
sudo apt update
sudo DEBIAN_FRONTEND=noninteractive apt install cmake build-essential git emscripten -y
- name: Select node version
uses: actions/setup-node@v3
with:
node-version: 14
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Prepare project
run: |
mkdir build && cd build
emcmake cmake \
-DBUILD_BPF=Off \
-DBUILD_DRIVER=Off \
-DBUILD_LIBSCAP_MODERN_BPF=OFF \
-DCMAKE_BUILD_TYPE=Release \
-DUSE_BUNDLED_DEPS=On \
-DFALCO_ETC_DIR=/etc/falco \
-DBUILD_FALCO_UNIT_TESTS=On \
-DFALCO_VERSION=${{ inputs.version }} \
..
- name: Build project
run: |
cd build
emmake make -j6 all
- name: Run unit Tests
run: |
cd build
node ./unit_tests/falco_unit_tests.js
- name: Build packages
run: |
cd build
emmake make -j6 package
- name: Upload Falco WASM package
uses: actions/upload-artifact@v3
with:
name: falco-${{ inputs.version }}-wasm.tar.gz
path: |
${{ github.workspace }}/build/falco-${{ inputs.version }}-wasm.tar.gz

View File

@@ -66,10 +66,14 @@ jobs:
run: |
docker push docker.io/falcosecurity/falco-no-driver:aarch64-${{ inputs.tag }}
docker push docker.io/falcosecurity/falco-no-driver:x86_64-${{ inputs.tag }}
docker push docker.io/falcosecurity/falco-distroless:aarch64-${{ inputs.tag }}
docker push docker.io/falcosecurity/falco-distroless:x86_64-${{ inputs.tag }}
docker push docker.io/falcosecurity/falco:aarch64-${{ inputs.tag }}
docker push docker.io/falcosecurity/falco:x86_64-${{ inputs.tag }}
docker push docker.io/falcosecurity/falco-driver-loader:aarch64-${{ inputs.tag }}
docker push docker.io/falcosecurity/falco-driver-loader:x86_64-${{ inputs.tag }}
docker push docker.io/falcosecurity/falco-driver-loader-legacy:aarch64-${{ inputs.tag }}
docker push docker.io/falcosecurity/falco-driver-loader-legacy:x86_64-${{ inputs.tag }}
- name: Create no-driver manifest on Docker Hub
uses: Noelware/docker-manifest-action@0.3.1
@@ -77,6 +81,13 @@ jobs:
inputs: docker.io/falcosecurity/falco-no-driver:${{ inputs.tag }}
images: docker.io/falcosecurity/falco-no-driver:aarch64-${{ inputs.tag }},docker.io/falcosecurity/falco-no-driver:x86_64-${{ inputs.tag }}
push: true
- name: Create distroless manifest on Docker Hub
uses: Noelware/docker-manifest-action@0.3.1
with:
inputs: docker.io/falcosecurity/falco-distroless:${{ inputs.tag }}
images: docker.io/falcosecurity/falco-distroless:aarch64-${{ inputs.tag }},docker.io/falcosecurity/falco-distroless:x86_64-${{ inputs.tag }}
push: true
- name: Tag slim manifest on Docker Hub
run: |
@@ -96,31 +107,46 @@ jobs:
images: docker.io/falcosecurity/falco-driver-loader:aarch64-${{ inputs.tag }},docker.io/falcosecurity/falco-driver-loader:x86_64-${{ inputs.tag }}
push: true
- name: Create falco-driver-loader-legacy manifest on Docker Hub
uses: Noelware/docker-manifest-action@0.3.1
with:
inputs: docker.io/falcosecurity/falco-driver-loader-legacy:${{ inputs.tag }}
images: docker.io/falcosecurity/falco-driver-loader-legacy:aarch64-${{ inputs.tag }},docker.io/falcosecurity/falco-driver-loader-legacy:x86_64-${{ inputs.tag }}
push: true
- name: Get Digests for images
id: digests
run: |
echo "falco-no-driver=$(crane digest docker.io/falcosecurity/falco-no-driver:${{ inputs.tag }})" >> $GITHUB_OUTPUT
echo "falco-distroless=$(crane digest docker.io/falcosecurity/falco-distroless:${{ inputs.tag }})" >> $GITHUB_OUTPUT
echo "falco=$(crane digest docker.io/falcosecurity/falco:${{ inputs.tag }})" >> $GITHUB_OUTPUT
echo "falco-driver-loader=$(crane digest docker.io/falcosecurity/falco-driver-loader:${{ inputs.tag }})" >> $GITHUB_OUTPUT
echo "falco-driver-loader-legacy=$(crane digest docker.io/falcosecurity/falco-driver-loader-legacy:${{ inputs.tag }})" >> $GITHUB_OUTPUT
- name: Publish images to ECR
run: |
crane copy docker.io/falcosecurity/falco-no-driver:${{ inputs.tag }} public.ecr.aws/falcosecurity/falco-no-driver:${{ inputs.tag }}
crane copy docker.io/falcosecurity/falco-distroless:${{ inputs.tag }} public.ecr.aws/falcosecurity/falco-distroless:${{ inputs.tag }}
crane copy docker.io/falcosecurity/falco:${{ inputs.tag }} public.ecr.aws/falcosecurity/falco:${{ inputs.tag }}
crane copy docker.io/falcosecurity/falco-driver-loader:${{ inputs.tag }} public.ecr.aws/falcosecurity/falco-driver-loader:${{ inputs.tag }}
crane copy docker.io/falcosecurity/falco-driver-loader-legacy:${{ inputs.tag }} public.ecr.aws/falcosecurity/falco-driver-loader-legacy:${{ inputs.tag }}
crane copy public.ecr.aws/falcosecurity/falco-no-driver:${{ inputs.tag }} public.ecr.aws/falcosecurity/falco:${{ inputs.tag }}-slim
- name: Tag latest on Docker Hub and ECR
if: inputs.is_latest
run: |
crane tag docker.io/falcosecurity/falco-no-driver:${{ inputs.tag }} latest
crane tag docker.io/falcosecurity/falco-distroless:${{ inputs.tag }} latest
crane tag docker.io/falcosecurity/falco:${{ inputs.tag }} latest
crane tag docker.io/falcosecurity/falco-driver-loader:${{ inputs.tag }} latest
crane tag docker.io/falcosecurity/falco-driver-loader-legacy:${{ inputs.tag }} latest
crane tag docker.io/falcosecurity/falco:${{ inputs.tag }}-slim latest-slim
crane tag public.ecr.aws/falcosecurity/falco-no-driver:${{ inputs.tag }} latest
crane tag public.ecr.aws/falcosecurity/falco-distroless:${{ inputs.tag }} latest
crane tag public.ecr.aws/falcosecurity/falco:${{ inputs.tag }} latest
crane tag public.ecr.aws/falcosecurity/falco-driver-loader:${{ inputs.tag }} latest
crane tag public.ecr.aws/falcosecurity/falco-driver-loader-legacy:${{ inputs.tag }} latest
crane tag public.ecr.aws/falcosecurity/falco:${{ inputs.tag }}-slim latest-slim
- name: Setup Cosign
@@ -136,9 +162,13 @@ jobs:
COSIGN_YES: "true"
run: |
cosign sign docker.io/falcosecurity/falco-no-driver@${{ steps.digests.outputs.falco-no-driver }}
cosign sign docker.io/falcosecurity/falco-distroless@${{ steps.digests.outputs.falco-distroless }}
cosign sign docker.io/falcosecurity/falco@${{ steps.digests.outputs.falco }}
cosign sign docker.io/falcosecurity/falco-driver-loader@${{ steps.digests.outputs.falco-driver-loader }}
cosign sign docker.io/falcosecurity/falco-driver-loader-legacy@${{ steps.digests.outputs.falco-driver-loader-legacy }}
cosign sign public.ecr.aws/falcosecurity/falco-no-driver@${{ steps.digests.outputs.falco-no-driver }}
cosign sign public.ecr.aws/falcosecurity/falco-distroless@${{ steps.digests.outputs.falco-distroless }}
cosign sign public.ecr.aws/falcosecurity/falco@${{ steps.digests.outputs.falco }}
cosign sign public.ecr.aws/falcosecurity/falco-driver-loader@${{ steps.digests.outputs.falco-driver-loader }}
cosign sign public.ecr.aws/falcosecurity/falco-driver-loader-legacy@${{ steps.digests.outputs.falco-driver-loader-legacy }}

View File

@@ -44,6 +44,13 @@ jobs:
cd falco-${{ inputs.version }}-${{ inputs.arch }}
sudo cp -r * /
# x86_64 job run on ubuntu-22.04 and here we can install kernel-headers
- name: Install dependencies for falco-driver-loader tests on x86
if: ${{ inputs.arch == 'x86_64' }}
run: |
sudo apt update -y
sudo apt install -y --no-install-recommends build-essential clang make llvm gcc dkms linux-headers-$(uname -r)
- name: Install go-junit-report
run: |
pushd submodules/falcosecurity-testing
@@ -56,13 +63,21 @@ jobs:
go generate ./...
popd
# Right now we are not able to install kernel-headers on our ARM64 self-hosted runner.
# For this reason, we disable the falco-driver-loader tests, which require kernel headers on the host.
- name: Run regression tests
env:
# fixme(leogr): this is a workaround for https://github.com/falcosecurity/falco/issues/2784
HOST_ROOT: ""
run: |
pushd submodules/falcosecurity-testing
./build/falco.test -falco-static=${{ inputs.static && 'true' || 'false' }} -test.timeout=90s -test.v >> ./report.txt 2>&1 || true
if ${{ inputs.static && 'false' || 'true' }}; then
./build/falcoctl.test -test.timeout=90s -test.v >> ./report.txt 2>&1 || true
./build/k8saudit.test -test.timeout=90s -test.v >> ./report.txt 2>&1 || true
if ${{ inputs.arch == 'x86_64' && 'true' || 'false' }}; then
sudo ./build/falco-driver-loader.test -test.timeout=90s -test.v >> ./report.txt 2>&1 || true
fi
fi
cat ./report.txt | go-junit-report -set-exit-code > report.xml
popd

View File

@@ -20,6 +20,14 @@ option(MINIMAL_BUILD "Build a minimal version of Falco, containing only the engi
option(MUSL_OPTIMIZED_BUILD "Enable if you want a musl optimized build" OFF)
option(BUILD_FALCO_UNIT_TESTS "Build falco unit tests" OFF)
if(EMSCRIPTEN)
set(USE_BUNDLED_DEPS ON CACHE BOOL "" FORCE)
set(BUILD_DRIVER OFF CACHE BOOL "" FORCE)
set(ENABLE_DKMS OFF CACHE BOOL "" FORCE)
set(BUILD_BPF OFF CACHE BOOL "" FORCE)
set(CPACK_GENERATOR TGZ CACHE BOOL "" FORCE)
endif()
# gVisor is currently only supported on Linux x86_64
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT MINIMAL_BUILD)
option(BUILD_FALCO_GVISOR "Build gVisor support for Falco" ON)
@@ -68,7 +76,11 @@ if(NOT DEFINED FALCO_ETC_DIR)
endif()
# This will be used to print the architecture for which Falco is compiled.
set(FALCO_TARGET_ARCH ${CMAKE_SYSTEM_PROCESSOR})
if (EMSCRIPTEN)
set(FALCO_TARGET_ARCH "wasm")
else()
set(FALCO_TARGET_ARCH ${CMAKE_SYSTEM_PROCESSOR})
endif()
if(NOT FALCO_EXTRA_DEBUG_FLAGS)
set(FALCO_EXTRA_DEBUG_FLAGS "-D_DEBUG")
@@ -95,7 +107,10 @@ endif()
# explicitly set hardening flags
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(FALCO_SECURITY_FLAGS "-Wl,-z,relro,-z,now -fstack-protector-strong")
set(FALCO_SECURITY_FLAGS "")
if(NOT EMSCRIPTEN)
set(FALCO_SECURITY_FLAGS "${FALCO_SECURITY_FLAGS} -Wl,-z,relro,-z,now -fstack-protector-strong")
endif()
if(CMAKE_BUILD_TYPE STREQUAL "release")
set(FALCO_SECURITY_FLAGS "${FALCO_SECURITY_FLAGS} -D_FORTIFY_SOURCE=2")
endif()
@@ -154,19 +169,17 @@ include(jq)
# nlohmann-json
include(njson)
# b64
include(b64)
# yaml-cpp
include(yaml-cpp)
if(NOT MINIMAL_BUILD)
if(NOT WIN32 AND NOT APPLE AND NOT MINIMAL_BUILD AND NOT EMSCRIPTEN)
# OpenSSL
include(openssl)
# libcurl
include(curl)
# todo(jasondellaluce,rohith-raju): support webserver for non-linux builds too
# cpp-httlib
include(cpp-httplib)
endif()
@@ -174,14 +187,18 @@ endif()
include(cxxopts)
# One TBB
include(tbb)
if (NOT EMSCRIPTEN)
include(tbb)
endif()
if(NOT MINIMAL_BUILD)
if (NOT MINIMAL_BUILD)
include(zlib)
include(cares)
include(protobuf)
# gRPC
include(grpc)
if (NOT WIN32 AND NOT APPLE AND NOT EMSCRIPTEN)
include(cares)
include(protobuf)
# gRPC
include(grpc)
endif()
endif()
# Installation
@@ -212,12 +229,11 @@ add_subdirectory(scripts)
add_subdirectory(userspace/engine)
add_subdirectory(userspace/falco)
if(NOT MUSL_OPTIMIZED_BUILD)
if(NOT WIN32 AND NOT APPLE AND NOT EMSCRIPTEN AND NOT MUSL_OPTIMIZED_BUILD)
include(plugins)
include(falcoctl)
endif()
include(falcoctl)
# Packages configuration
include(CPackConfig)

View File

@@ -46,8 +46,7 @@ Considerations and guidance for Falco adopters:
## How to Contribute
Please refer to the [contributing guide](https://github.com/falcosecurity/.github/blob/main/CONTRIBUTING.md) and the [code of conduct](https://github.com/falcosecurity/evolution/CODE_OF_CONDUCT.md) for more information on how to contribute.
Please refer to the [contributing guide](https://github.com/falcosecurity/.github/blob/main/CONTRIBUTING.md) and the [code of conduct](https://github.com/falcosecurity/evolution/blob/main/CODE_OF_CONDUCT.md) for more information on how to contribute.
## Join the Community
@@ -73,11 +72,24 @@ To report security vulnerabilities, please follow the community process outlined
Stay updated with Falco's evolving capabilities by exploring the [Falco Roadmap](https://github.com/orgs/falcosecurity/projects/5), which provides insights into the features currently under development and planned for future releases.
## License
Falco is licensed to you under the [Apache 2.0](./COPYING) open source license.
## Why is Falco in C++ rather than Go or {language}?
1. The first lines of code at the base of Falco were written some time ago, where Go didn't yet have the same level of maturity and adoption as today.
2. The Falco execution model is sequential and mono-thread due to the statefulness requirements of the tool, and so most of the concurrency-related selling points of the Go runtime would not be leveraged at all.
3. The Falco code deals with very low-level programming in many places (e.g. some headers are shared with the eBPF probe and the Kernel module), and we all know that interfacing Go with C is possible but brings tons of complexity and tradeoffs to the table.
4. As a security tool meant to consume a crazy high throughput of events per second, Falco needs to squeeze performance in all hot paths at runtime and requires deep control on memory allocation, which the Go runtime can't provide (there's also garbage collection involved).
5. Although Go didn't suit the engineering requirements of the core of Falco, we still thought that it could be a good candidate for writing Falco extensions through the plugin system. This is the main reason we gave special attention and high priority to the development of the plugin-sdk-go.
6. Go is not a requirement for having statically-linked binaries. In fact, we provide fully-static Falco builds since few years. The only issue with those is that the plugin system can't be supported with the current dynamic library model we currently have.
7. The plugin system has been envisioned to support multiple languages, so on our end maintaining a C-compatible codebase is the best strategy to ensure maximum cross-language compatibility.
8. In general, plugins have GLIBC requirements/dependencies because they have low-level C bindings required for dynamic loading. A potential solution for the future could be to also support plugin to be statically-linked at compilation time and so released as bundled in the Falco binary. Although no work started yet in this direction, this would solve most issues you reported and would provide a totally-static binary too. Of course, this would not be compatible with dynamic loading anymore, but it may be a viable solution for our static-build flavor of Falco.
9. Memory safety is definitely a concern and we try our best to keep an high level of quality even though C++ is quite error prone. For instance, we try to use smart pointers whenever possible, we build the libraries with an address sanitizer in our CI, we run Falco through Valgrind before each release, and have ways to stress-test it to detect performance regressions or weird memory usage (e.g. https://github.com/falcosecurity/event-generator). On top of that, we also have third parties auditing the codebase by time to time. None of this make a perfect safety standpoint of course, but we try to maximize our odds. Go would definitely make our life easier from this perspective, however the tradeoffs never made it worth it so far due to the points above.
10. The C++ codebase of falcosecurity/libs, which is at the core of Falco, is quite large and complex. Porting all that code to another language would be a major effort requiring lots of development resource and with an high chance of failure and regression. As such, our approach so far has been to choose refactors and code polishing instead, up until we'll reach an optimal level of stability, quality, and modularity, on that portion of code. This would allow further developments to be smoother and more feasibile in the future.
## Resources
- [Governance](https://github.com/falcosecurity/evolution/blob/main/GOVERNANCE.md)

View File

@@ -20,24 +20,36 @@ set(CPACK_PACKAGE_VERSION "${FALCO_VERSION}")
set(CPACK_PACKAGE_VERSION_MAJOR "${FALCO_VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${FALCO_VERSION_MINOR}")
set(CPACK_PACKAGE_VERSION_PATCH "${FALCO_VERSION_PATCH}")
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_SYSTEM_PROCESSOR}")
set(CPACK_PROJECT_CONFIG_FILE "${PROJECT_SOURCE_DIR}/cmake/cpack/CMakeCPackOptions.cmake")
set(CPACK_STRIP_FILES "ON")
set(CPACK_PACKAGE_RELOCATABLE "OFF")
if (EMSCRIPTEN)
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-wasm")
else()
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_SYSTEM_PROCESSOR}")
endif()
# Built packages will include only the following components
set(CPACK_INSTALL_CMAKE_PROJECTS
"${CMAKE_CURRENT_BINARY_DIR};${FALCO_COMPONENT_NAME};${FALCO_COMPONENT_NAME};/"
"${CMAKE_CURRENT_BINARY_DIR};${DRIVER_COMPONENT_NAME};${DRIVER_COMPONENT_NAME};/"
"${CMAKE_CURRENT_BINARY_DIR};${FALCO_COMPONENT_NAME};${FALCO_COMPONENT_NAME};/"
)
if(NOT MUSL_OPTIMIZED_BUILD) # static builds do not have plugins
if(CMAKE_SYSTEM_NAME MATCHES "Linux") # only Linux has drivers
list(APPEND CPACK_INSTALL_CMAKE_PROJECTS
"${CMAKE_CURRENT_BINARY_DIR};${PLUGINS_COMPONENT_NAME};${PLUGINS_COMPONENT_NAME};/"
)
"${CMAKE_CURRENT_BINARY_DIR};${DRIVER_COMPONENT_NAME};${DRIVER_COMPONENT_NAME};/")
endif()
if(NOT WIN32 AND NOT APPLE AND NOT EMSCRIPTEN AND NOT MUSL_OPTIMIZED_BUILD) # static builds do not have plugins
list(APPEND CPACK_INSTALL_CMAKE_PROJECTS
"${CMAKE_CURRENT_BINARY_DIR};${PLUGINS_COMPONENT_NAME};${PLUGINS_COMPONENT_NAME};/")
endif()
if(NOT CPACK_GENERATOR)
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
set(CPACK_GENERATOR DEB RPM TGZ)
else()
set(CPACK_GENERATOR TGZ)
endif()
endif()
message(STATUS "Using package generators: ${CPACK_GENERATOR}")

View File

@@ -15,11 +15,12 @@ cmake_minimum_required(VERSION 3.5.1)
project(driver-repo NONE)
include(ExternalProject)
message(STATUS "Driver repository: ${DRIVER_REPO}")
message(STATUS "Driver version: ${DRIVER_VERSION}")
ExternalProject_Add(
driver
URL "https://github.com/falcosecurity/libs/archive/${DRIVER_VERSION}.tar.gz"
URL "https://github.com/${DRIVER_REPO}/archive/${DRIVER_VERSION}.tar.gz"
URL_HASH "${DRIVER_CHECKSUM}"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""

View File

@@ -20,18 +20,29 @@ if(DRIVER_SOURCE_DIR)
set(DRIVER_VERSION "0.0.0-local")
message(STATUS "Using local version for driver: '${DRIVER_SOURCE_DIR}'")
else()
# DRIVER_REPO accepts a repository name (<org name>/<repo name>) alternative to the falcosecurity/libs repository.
# In case you want to test against a fork of falcosecurity/libs just pass the variable -
# ie., `cmake -DDRIVER_REPO=<your-gh-handle>/libs ..`
if (NOT DRIVER_REPO)
set(DRIVER_REPO "falcosecurity/libs")
endif()
# DRIVER_VERSION accepts a git reference (branch name, commit hash, or tag) to the falcosecurity/libs repository
# which contains the driver source code under the `/driver` directory.
# The chosen driver version must be compatible with the given FALCOSECURITY_LIBS_VERSION.
# In case you want to test against another driver version (or branch, or commit) just pass the variable -
# ie., `cmake -DDRIVER_VERSION=dev ..`
if(NOT DRIVER_VERSION)
set(DRIVER_VERSION "942a2249b7b9f65def0a01acfb1fba84f629b3bf")
set(DRIVER_CHECKSUM "SHA256=8670d7b24fad659674cea90b9b3d86e5d0775a6b2faedc0d5303f910242282ff")
set(DRIVER_VERSION "6.0.0+driver")
set(DRIVER_CHECKSUM "SHA256=573cef7b9c69cfe1d5d8b873d2a20ad8235a2a96997df6bcebd120692dee7a91")
endif()
# cd /path/to/build && cmake /path/to/source
execute_process(COMMAND "${CMAKE_COMMAND}" -DDRIVER_VERSION=${DRIVER_VERSION} -DDRIVER_CHECKSUM=${DRIVER_CHECKSUM}
execute_process(COMMAND "${CMAKE_COMMAND}"
-DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}"
-DDRIVER_REPO=${DRIVER_REPO}
-DDRIVER_VERSION=${DRIVER_VERSION}
-DDRIVER_CHECKSUM=${DRIVER_CHECKSUM}
${DRIVER_CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${DRIVER_CMAKE_WORKING_DIR})
# cmake --build .

View File

@@ -15,14 +15,14 @@ include(ExternalProject)
string(TOLOWER ${CMAKE_HOST_SYSTEM_NAME} FALCOCTL_SYSTEM_NAME)
set(FALCOCTL_VERSION "0.5.1")
set(FALCOCTL_VERSION "0.6.0")
if(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64")
set(FALCOCTL_SYSTEM_PROC_GO "amd64")
set(FALCOCTL_HASH "ea7c89134dc745a1cbdbcf8f839d3b47851a40e1aebee20702a606b03b45b897")
set(FALCOCTL_HASH "b81c36449b525e1de871288741beeadead021ac133d9b306f0636be1befe58a5")
else() # aarch64
set(FALCOCTL_SYSTEM_PROC_GO "arm64")
set(FALCOCTL_HASH "22797200bf0e4c7c45f69207ed85218a3839115a302dc07939d3006778d41300")
set(FALCOCTL_HASH "6e99fd765f67cdd46fa8c5b2969e97497856d2e615698ced04046c8898187b18")
endif()
ExternalProject_Add(

View File

@@ -15,11 +15,12 @@ cmake_minimum_required(VERSION 3.5.1)
project(falcosecurity-libs-repo NONE)
include(ExternalProject)
message(STATUS "Libs repository: ${FALCOSECURITY_LIBS_REPO}")
message(STATUS "Libs version: ${FALCOSECURITY_LIBS_VERSION}")
ExternalProject_Add(
falcosecurity-libs
URL "https://github.com/falcosecurity/libs/archive/${FALCOSECURITY_LIBS_VERSION}.tar.gz"
URL "https://github.com/${FALCOSECURITY_LIBS_REPO}/archive/${FALCOSECURITY_LIBS_VERSION}.tar.gz"
URL_HASH "${FALCOSECURITY_LIBS_CHECKSUM}"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""

View File

@@ -23,17 +23,25 @@ if(FALCOSECURITY_LIBS_SOURCE_DIR)
set(FALCOSECURITY_LIBS_VERSION "0.0.0-local")
message(STATUS "Using local version of falcosecurity/libs: '${FALCOSECURITY_LIBS_SOURCE_DIR}'")
else()
# FALCOSECURITY_LIBS_REPO accepts a repository name (<org name>/<repo name>) alternative to the falcosecurity/libs repository.
# In case you want to test against a fork of falcosecurity/libs just pass the variable -
# ie., `cmake -DFALCOSECURITY_LIBS_REPO=<your-gh-handle>/libs ..`
if (NOT FALCOSECURITY_LIBS_REPO)
set(FALCOSECURITY_LIBS_REPO "falcosecurity/libs")
endif()
# FALCOSECURITY_LIBS_VERSION accepts a git reference (branch name, commit hash, or tag) to the falcosecurity/libs repository.
# In case you want to test against another falcosecurity/libs version (or branch, or commit) just pass the variable -
# ie., `cmake -DFALCOSECURITY_LIBS_VERSION=dev ..`
if(NOT FALCOSECURITY_LIBS_VERSION)
set(FALCOSECURITY_LIBS_VERSION "942a2249b7b9f65def0a01acfb1fba84f629b3bf")
set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=8670d7b24fad659674cea90b9b3d86e5d0775a6b2faedc0d5303f910242282ff")
set(FALCOSECURITY_LIBS_VERSION "0.13.0-rc1")
set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=a75526b664bce2ba05912e056e48be39b0b1cb797b2055d107e55afbee2c8233")
endif()
# cd /path/to/build && cmake /path/to/source
execute_process(COMMAND "${CMAKE_COMMAND}"
-DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}"
-DFALCOSECURITY_LIBS_REPO=${FALCOSECURITY_LIBS_REPO}
-DFALCOSECURITY_LIBS_VERSION=${FALCOSECURITY_LIBS_VERSION}
-DFALCOSECURITY_LIBS_CHECKSUM=${FALCOSECURITY_LIBS_CHECKSUM}
${FALCOSECURITY_LIBS_CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${FALCOSECURITY_LIBS_CMAKE_WORKING_DIR})
@@ -45,8 +53,10 @@ endif()
set(LIBS_PACKAGE_NAME "falcosecurity")
add_definitions(-D_GNU_SOURCE)
add_definitions(-DHAS_CAPTURE)
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
add_definitions(-D_GNU_SOURCE)
add_definitions(-DHAS_CAPTURE)
endif()
if(MUSL_OPTIMIZED_BUILD)
add_definitions(-DMUSL_OPTIMIZED)

View File

@@ -15,8 +15,8 @@ include(GNUInstallDirs)
include(ExternalProject)
# falco_rules.yaml
set(FALCOSECURITY_RULES_FALCO_VERSION "falco-rules-1.0.1")
set(FALCOSECURITY_RULES_FALCO_CHECKSUM "SHA256=2348d43196bbbdea92e3f67fa928721a241b0406d0ef369693bdefcec2b3fa13")
set(FALCOSECURITY_RULES_FALCO_VERSION "falco-rules-2.0.0-rc1")
set(FALCOSECURITY_RULES_FALCO_CHECKSUM "SHA256=1e5cda24238bb33e7fdb55a523d39fe8eac3978822fca9ce073c6bd537b86ecf")
set(FALCOSECURITY_RULES_FALCO_PATH "${PROJECT_BINARY_DIR}/falcosecurity-rules-falco-prefix/src/falcosecurity-rules-falco/falco_rules.yaml")
ExternalProject_Add(
falcosecurity-rules-falco

View File

@@ -9,3 +9,7 @@ This directory contains various ways to package Falco as a container and related
| [falcosecurity/falco:latest](https://hub.docker.com/repository/docker/falcosecurity/falco), [falcosecurity/falco:_tag_](https://hub.docker.com/repository/docker/falcosecurity/falco), [falcosecurity/falco:master](https://hub.docker.com/repository/docker/falcosecurity/falco) | docker/falco | Falco (DEB built from git tag or from the master) with all the building toolchain. |
| [falcosecurity/falco-driver-loader:latest](https://hub.docker.com/repository/docker/falcosecurity/falco-driver-loader), [falcosecurity/falco-driver-loader:_tag_](https://hub.docker.com/repository/docker/falcosecurity/falco-driver-loader), [falcosecurity/falco-driver-loader:master](https://hub.docker.com/repository/docker/falcosecurity/falco-driver-loader) | docker/driver-loader | `falco-driver-loader` as entrypoint with the building toolchain. |
| [falcosecurity/falco-no-driver:latest](https://hub.docker.com/repository/docker/falcosecurity/falco-no-driver), [falcosecurity/falco-no-driver:_tag_](https://hub.docker.com/repository/docker/falcosecurity/falco-no-driver),[falcosecurity/falco-no-driver:master](https://hub.docker.com/repository/docker/falcosecurity/falco-no-driver) | docker/no-driver | Falco (TGZ built from git tag or from the master) without the building toolchain. |
## Experimental Images
| [falcosecurity/falco-distroless:latest](https://hub.docker.com/repository/docker/falcosecurity/falco-distroless), [falcosecurity/falco-distroless:_tag_](https://hub.docker.com/repository/docker/falcosecurity/falco-distroless),[falcosecurity/falco-distroless:master](https://hub.docker.com/repository/docker/falcosecurity/falco-distroless) | docker/no-driver/Dockerfile.distroless | Falco without the building toolchain built from a distroless base image. This results in a smaller image that has less potentially vulnerable components. |

View File

@@ -0,0 +1,130 @@
FROM debian:buster
LABEL maintainer="cncf-falco-dev@lists.cncf.io"
LABEL org.opencontainers.image.source="https://github.com/falcosecurity/falco"
LABEL usage="docker run -i -t --privileged -v /var/run/docker.sock:/host/var/run/docker.sock -v /dev:/host/dev -v /proc:/host/proc:ro -v /boot:/host/boot:ro -v /lib/modules:/host/lib/modules:ro -v /usr:/host/usr:ro -v /etc:/host/etc --name NAME IMAGE"
ARG TARGETARCH
ARG FALCO_VERSION=latest
ARG VERSION_BUCKET=deb
ENV VERSION_BUCKET=${VERSION_BUCKET}
ENV FALCO_VERSION=${FALCO_VERSION}
ENV HOST_ROOT /host
ENV HOME /root
RUN cp /etc/skel/.bashrc /root && cp /etc/skel/.profile /root
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
bash-completion \
bc \
bison \
clang-7 \
ca-certificates \
curl \
dkms \
flex \
gnupg2 \
gcc \
jq \
libc6-dev \
libelf-dev \
libssl-dev \
llvm-7 \
netcat \
patchelf \
xz-utils \
&& rm -rf /var/lib/apt/lists/*
RUN if [ "$TARGETARCH" = "amd64" ]; \
then apt-get install -y --no-install-recommends libmpx2; \
fi
# gcc 6 is no longer included in debian stable, but we need it to
# build kernel modules on the default debian-based ami used by
# kops. So grab copies we've saved from debian snapshots with the
# prefix https://snapshot.debian.org/archive/debian/20170517T033514Z
# or so.
RUN if [ "$TARGETARCH" = "amd64" ]; then curl -L -o libcilkrts5_6.3.0-18_${TARGETARCH}.deb https://download.falco.org/dependencies/libcilkrts5_6.3.0-18_${TARGETARCH}.deb; fi; \
curl -L -o cpp-6_6.3.0-18_${TARGETARCH}.deb https://download.falco.org/dependencies/cpp-6_6.3.0-18_${TARGETARCH}.deb \
&& curl -L -o gcc-6-base_6.3.0-18_${TARGETARCH}.deb https://download.falco.org/dependencies/gcc-6-base_6.3.0-18_${TARGETARCH}.deb \
&& curl -L -o gcc-6_6.3.0-18_${TARGETARCH}.deb https://download.falco.org/dependencies/gcc-6_6.3.0-18_${TARGETARCH}.deb \
&& curl -L -o libasan3_6.3.0-18_${TARGETARCH}.deb https://download.falco.org/dependencies/libasan3_6.3.0-18_${TARGETARCH}.deb \
&& curl -L -o libgcc-6-dev_6.3.0-18_${TARGETARCH}.deb https://download.falco.org/dependencies/libgcc-6-dev_6.3.0-18_${TARGETARCH}.deb \
&& curl -L -o libubsan0_6.3.0-18_${TARGETARCH}.deb https://download.falco.org/dependencies/libubsan0_6.3.0-18_${TARGETARCH}.deb \
&& curl -L -o libmpfr4_3.1.3-2_${TARGETARCH}.deb https://download.falco.org/dependencies/libmpfr4_3.1.3-2_${TARGETARCH}.deb \
&& curl -L -o libisl15_0.18-1_${TARGETARCH}.deb https://download.falco.org/dependencies/libisl15_0.18-1_${TARGETARCH}.deb \
&& dpkg -i cpp-6_6.3.0-18_${TARGETARCH}.deb gcc-6-base_6.3.0-18_${TARGETARCH}.deb gcc-6_6.3.0-18_${TARGETARCH}.deb libasan3_6.3.0-18_${TARGETARCH}.deb; \
if [ "$TARGETARCH" = "amd64" ]; then dpkg -i libcilkrts5_6.3.0-18_${TARGETARCH}.deb; fi; \
dpkg -i libgcc-6-dev_6.3.0-18_${TARGETARCH}.deb libubsan0_6.3.0-18_${TARGETARCH}.deb libmpfr4_3.1.3-2_${TARGETARCH}.deb libisl15_0.18-1_${TARGETARCH}.deb \
&& rm -f cpp-6_6.3.0-18_${TARGETARCH}.deb gcc-6-base_6.3.0-18_${TARGETARCH}.deb gcc-6_6.3.0-18_${TARGETARCH}.deb libasan3_6.3.0-18_${TARGETARCH}.deb libcilkrts5_6.3.0-18_${TARGETARCH}.deb libgcc-6-dev_6.3.0-18_${TARGETARCH}.deb libubsan0_6.3.0-18_${TARGETARCH}.deb libmpfr4_3.1.3-2_${TARGETARCH}.deb libisl15_0.18-1_${TARGETARCH}.deb
# gcc 5 is no longer included in debian stable, but we need it to
# build centos kernels, which are 3.x based and explicitly want a gcc
# version 3, 4, or 5 compiler. So grab copies we've saved from debian
# snapshots with the prefix https://snapshot.debian.org/archive/debian/20190122T000000Z.
RUN if [ "$TARGETARCH" = "amd64" ]; then curl -L -o libmpx0_5.5.0-12_${TARGETARCH}.deb https://download.falco.org/dependencies/libmpx0_5.5.0-12_${TARGETARCH}.deb; fi; \
curl -L -o cpp-5_5.5.0-12_${TARGETARCH}.deb https://download.falco.org/dependencies/cpp-5_5.5.0-12_${TARGETARCH}.deb \
&& curl -L -o gcc-5-base_5.5.0-12_${TARGETARCH}.deb https://download.falco.org/dependencies/gcc-5-base_5.5.0-12_${TARGETARCH}.deb \
&& curl -L -o gcc-5_5.5.0-12_${TARGETARCH}.deb https://download.falco.org/dependencies/gcc-5_5.5.0-12_${TARGETARCH}.deb \
&& curl -L -o libasan2_5.5.0-12_${TARGETARCH}.deb https://download.falco.org/dependencies/libasan2_5.5.0-12_${TARGETARCH}.deb \
&& curl -L -o libgcc-5-dev_5.5.0-12_${TARGETARCH}.deb https://download.falco.org/dependencies/libgcc-5-dev_5.5.0-12_${TARGETARCH}.deb \
&& curl -L -o libisl15_0.18-4_${TARGETARCH}.deb https://download.falco.org/dependencies/libisl15_0.18-4_${TARGETARCH}.deb \
&& dpkg -i cpp-5_5.5.0-12_${TARGETARCH}.deb gcc-5-base_5.5.0-12_${TARGETARCH}.deb gcc-5_5.5.0-12_${TARGETARCH}.deb libasan2_5.5.0-12_${TARGETARCH}.deb; \
if [ "$TARGETARCH" = "amd64" ]; then dpkg -i libmpx0_5.5.0-12_${TARGETARCH}.deb; fi; \
dpkg -i libgcc-5-dev_5.5.0-12_${TARGETARCH}.deb libisl15_0.18-4_${TARGETARCH}.deb \
&& rm -f cpp-5_5.5.0-12_${TARGETARCH}.deb gcc-5-base_5.5.0-12_${TARGETARCH}.deb gcc-5_5.5.0-12_${TARGETARCH}.deb libasan2_5.5.0-12_${TARGETARCH}.deb libgcc-5-dev_5.5.0-12_${TARGETARCH}.deb libisl15_0.18-4_${TARGETARCH}.deb libmpx0_5.5.0-12_${TARGETARCH}.deb
# Since our base Debian image ships with GCC 7 which breaks older kernels, revert the
# default to gcc-5.
RUN rm -rf /usr/bin/gcc && ln -s /usr/bin/gcc-5 /usr/bin/gcc
RUN rm -rf /usr/bin/clang \
&& rm -rf /usr/bin/llc \
&& ln -s /usr/bin/clang-7 /usr/bin/clang \
&& ln -s /usr/bin/llc-7 /usr/bin/llc
RUN curl -s https://falco.org/repo/falcosecurity-packages.asc | apt-key add - \
&& echo "deb https://download.falco.org/packages/${VERSION_BUCKET} stable main" | tee -a /etc/apt/sources.list.d/falcosecurity.list \
&& apt-get update -y \
&& if [ "$FALCO_VERSION" = "latest" ]; then apt-get install -y --no-install-recommends falco; else apt-get install -y --no-install-recommends falco=${FALCO_VERSION}; fi \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Change the falco config within the container to enable ISO 8601
# output.
RUN sed -e 's/time_format_iso_8601: false/time_format_iso_8601: true/' < /etc/falco/falco.yaml > /etc/falco/falco.yaml.new \
&& mv /etc/falco/falco.yaml.new /etc/falco/falco.yaml
# Some base images have an empty /lib/modules by default
# If it's not empty, docker build will fail instead of
# silently overwriting the existing directory
RUN rm -df /lib/modules \
&& ln -s $HOST_ROOT/lib/modules /lib/modules
# debian:stable head contains binutils 2.31, which generates
# binaries that are incompatible with kernels < 4.16. So manually
# forcibly install binutils 2.30-22 instead.
RUN if [ "$TARGETARCH" = "amd64" ] ; then \
curl -L -o binutils-x86-64-linux-gnu_2.30-22_${TARGETARCH}.deb https://download.falco.org/dependencies/binutils-x86-64-linux-gnu_2.30-22_${TARGETARCH}.deb; \
else \
curl -L -o binutils-aarch64-linux-gnu_2.30-22_${TARGETARCH}.deb https://download.falco.org/dependencies/binutils-aarch64-linux-gnu_2.30-22_${TARGETARCH}.deb; \
fi
RUN curl -L -o binutils_2.30-22_${TARGETARCH}.deb https://download.falco.org/dependencies/binutils_2.30-22_${TARGETARCH}.deb \
&& curl -L -o libbinutils_2.30-22_${TARGETARCH}.deb https://download.falco.org/dependencies/libbinutils_2.30-22_${TARGETARCH}.deb \
&& curl -L -o binutils-common_2.30-22_${TARGETARCH}.deb https://download.falco.org/dependencies/binutils-common_2.30-22_${TARGETARCH}.deb \
&& dpkg -i *binutils*.deb \
&& rm -f *binutils*.deb
COPY ./docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["/usr/bin/falco"]

View File

@@ -0,0 +1,33 @@
#!/usr/bin/env bash
#
# Copyright (C) 2020 The Falco Authors.
#
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Set the SKIP_DRIVER_LOADER variable to skip loading the driver
if [[ -z "${SKIP_DRIVER_LOADER}" ]]; then
echo "* Setting up /usr/src links from host"
for i in "$HOST_ROOT/usr/src"/*
do
base=$(basename "$i")
ln -s "$i" "/usr/src/$base"
done
/usr/bin/falco-driver-loader
fi
exec "$@"

View File

@@ -1,4 +1,4 @@
FROM debian:buster
FROM debian:bookworm
LABEL maintainer="cncf-falco-dev@lists.cncf.io"
LABEL org.opencontainers.image.source="https://github.com/falcosecurity/falco"
@@ -19,76 +19,19 @@ RUN cp /etc/skel/.bashrc /root && cp /etc/skel/.profile /root
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
bash-completion \
bc \
bison \
clang-7 \
ca-certificates \
clang \
curl \
dkms \
flex \
gnupg2 \
gcc \
gcc-11 \
gnupg2 \
jq \
libc6-dev \
libelf-dev \
libssl-dev \
llvm-7 \
netcat \
patchelf \
xz-utils \
libelf1 \
llvm \
make \
&& rm -rf /var/lib/apt/lists/*
RUN if [ "$TARGETARCH" = "amd64" ]; \
then apt-get install -y --no-install-recommends libmpx2; \
fi
# gcc 6 is no longer included in debian stable, but we need it to
# build kernel modules on the default debian-based ami used by
# kops. So grab copies we've saved from debian snapshots with the
# prefix https://snapshot.debian.org/archive/debian/20170517T033514Z
# or so.
RUN if [ "$TARGETARCH" = "amd64" ]; then curl -L -o libcilkrts5_6.3.0-18_${TARGETARCH}.deb https://download.falco.org/dependencies/libcilkrts5_6.3.0-18_${TARGETARCH}.deb; fi; \
curl -L -o cpp-6_6.3.0-18_${TARGETARCH}.deb https://download.falco.org/dependencies/cpp-6_6.3.0-18_${TARGETARCH}.deb \
&& curl -L -o gcc-6-base_6.3.0-18_${TARGETARCH}.deb https://download.falco.org/dependencies/gcc-6-base_6.3.0-18_${TARGETARCH}.deb \
&& curl -L -o gcc-6_6.3.0-18_${TARGETARCH}.deb https://download.falco.org/dependencies/gcc-6_6.3.0-18_${TARGETARCH}.deb \
&& curl -L -o libasan3_6.3.0-18_${TARGETARCH}.deb https://download.falco.org/dependencies/libasan3_6.3.0-18_${TARGETARCH}.deb \
&& curl -L -o libgcc-6-dev_6.3.0-18_${TARGETARCH}.deb https://download.falco.org/dependencies/libgcc-6-dev_6.3.0-18_${TARGETARCH}.deb \
&& curl -L -o libubsan0_6.3.0-18_${TARGETARCH}.deb https://download.falco.org/dependencies/libubsan0_6.3.0-18_${TARGETARCH}.deb \
&& curl -L -o libmpfr4_3.1.3-2_${TARGETARCH}.deb https://download.falco.org/dependencies/libmpfr4_3.1.3-2_${TARGETARCH}.deb \
&& curl -L -o libisl15_0.18-1_${TARGETARCH}.deb https://download.falco.org/dependencies/libisl15_0.18-1_${TARGETARCH}.deb \
&& dpkg -i cpp-6_6.3.0-18_${TARGETARCH}.deb gcc-6-base_6.3.0-18_${TARGETARCH}.deb gcc-6_6.3.0-18_${TARGETARCH}.deb libasan3_6.3.0-18_${TARGETARCH}.deb; \
if [ "$TARGETARCH" = "amd64" ]; then dpkg -i libcilkrts5_6.3.0-18_${TARGETARCH}.deb; fi; \
dpkg -i libgcc-6-dev_6.3.0-18_${TARGETARCH}.deb libubsan0_6.3.0-18_${TARGETARCH}.deb libmpfr4_3.1.3-2_${TARGETARCH}.deb libisl15_0.18-1_${TARGETARCH}.deb \
&& rm -f cpp-6_6.3.0-18_${TARGETARCH}.deb gcc-6-base_6.3.0-18_${TARGETARCH}.deb gcc-6_6.3.0-18_${TARGETARCH}.deb libasan3_6.3.0-18_${TARGETARCH}.deb libcilkrts5_6.3.0-18_${TARGETARCH}.deb libgcc-6-dev_6.3.0-18_${TARGETARCH}.deb libubsan0_6.3.0-18_${TARGETARCH}.deb libmpfr4_3.1.3-2_${TARGETARCH}.deb libisl15_0.18-1_${TARGETARCH}.deb
# gcc 5 is no longer included in debian stable, but we need it to
# build centos kernels, which are 3.x based and explicitly want a gcc
# version 3, 4, or 5 compiler. So grab copies we've saved from debian
# snapshots with the prefix https://snapshot.debian.org/archive/debian/20190122T000000Z.
RUN if [ "$TARGETARCH" = "amd64" ]; then curl -L -o libmpx0_5.5.0-12_${TARGETARCH}.deb https://download.falco.org/dependencies/libmpx0_5.5.0-12_${TARGETARCH}.deb; fi; \
curl -L -o cpp-5_5.5.0-12_${TARGETARCH}.deb https://download.falco.org/dependencies/cpp-5_5.5.0-12_${TARGETARCH}.deb \
&& curl -L -o gcc-5-base_5.5.0-12_${TARGETARCH}.deb https://download.falco.org/dependencies/gcc-5-base_5.5.0-12_${TARGETARCH}.deb \
&& curl -L -o gcc-5_5.5.0-12_${TARGETARCH}.deb https://download.falco.org/dependencies/gcc-5_5.5.0-12_${TARGETARCH}.deb \
&& curl -L -o libasan2_5.5.0-12_${TARGETARCH}.deb https://download.falco.org/dependencies/libasan2_5.5.0-12_${TARGETARCH}.deb \
&& curl -L -o libgcc-5-dev_5.5.0-12_${TARGETARCH}.deb https://download.falco.org/dependencies/libgcc-5-dev_5.5.0-12_${TARGETARCH}.deb \
&& curl -L -o libisl15_0.18-4_${TARGETARCH}.deb https://download.falco.org/dependencies/libisl15_0.18-4_${TARGETARCH}.deb \
&& dpkg -i cpp-5_5.5.0-12_${TARGETARCH}.deb gcc-5-base_5.5.0-12_${TARGETARCH}.deb gcc-5_5.5.0-12_${TARGETARCH}.deb libasan2_5.5.0-12_${TARGETARCH}.deb; \
if [ "$TARGETARCH" = "amd64" ]; then dpkg -i libmpx0_5.5.0-12_${TARGETARCH}.deb; fi; \
dpkg -i libgcc-5-dev_5.5.0-12_${TARGETARCH}.deb libisl15_0.18-4_${TARGETARCH}.deb \
&& rm -f cpp-5_5.5.0-12_${TARGETARCH}.deb gcc-5-base_5.5.0-12_${TARGETARCH}.deb gcc-5_5.5.0-12_${TARGETARCH}.deb libasan2_5.5.0-12_${TARGETARCH}.deb libgcc-5-dev_5.5.0-12_${TARGETARCH}.deb libisl15_0.18-4_${TARGETARCH}.deb libmpx0_5.5.0-12_${TARGETARCH}.deb
# Since our base Debian image ships with GCC 7 which breaks older kernels, revert the
# default to gcc-5.
RUN rm -rf /usr/bin/gcc && ln -s /usr/bin/gcc-5 /usr/bin/gcc
RUN rm -rf /usr/bin/clang \
&& rm -rf /usr/bin/llc \
&& ln -s /usr/bin/clang-7 /usr/bin/clang \
&& ln -s /usr/bin/llc-7 /usr/bin/llc
RUN curl -s https://falco.org/repo/falcosecurity-packages.asc | apt-key add - \
&& echo "deb https://download.falco.org/packages/${VERSION_BUCKET} stable main" | tee -a /etc/apt/sources.list.d/falcosecurity.list \
&& apt-get update -y \
@@ -107,22 +50,6 @@ RUN sed -e 's/time_format_iso_8601: false/time_format_iso_8601: true/' < /etc/fa
RUN rm -df /lib/modules \
&& ln -s $HOST_ROOT/lib/modules /lib/modules
# debian:stable head contains binutils 2.31, which generates
# binaries that are incompatible with kernels < 4.16. So manually
# forcibly install binutils 2.30-22 instead.
RUN if [ "$TARGETARCH" = "amd64" ] ; then \
curl -L -o binutils-x86-64-linux-gnu_2.30-22_${TARGETARCH}.deb https://download.falco.org/dependencies/binutils-x86-64-linux-gnu_2.30-22_${TARGETARCH}.deb; \
else \
curl -L -o binutils-aarch64-linux-gnu_2.30-22_${TARGETARCH}.deb https://download.falco.org/dependencies/binutils-aarch64-linux-gnu_2.30-22_${TARGETARCH}.deb; \
fi
RUN curl -L -o binutils_2.30-22_${TARGETARCH}.deb https://download.falco.org/dependencies/binutils_2.30-22_${TARGETARCH}.deb \
&& curl -L -o libbinutils_2.30-22_${TARGETARCH}.deb https://download.falco.org/dependencies/libbinutils_2.30-22_${TARGETARCH}.deb \
&& curl -L -o binutils-common_2.30-22_${TARGETARCH}.deb https://download.falco.org/dependencies/binutils-common_2.30-22_${TARGETARCH}.deb \
&& dpkg -i *binutils*.deb \
&& rm -f *binutils*.deb
COPY ./docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]

View File

@@ -27,7 +27,10 @@ if [[ -z "${SKIP_DRIVER_LOADER}" ]]; then
ln -s "$i" "/usr/src/$base"
done
/usr/bin/falco-driver-loader
# convert the optional space-separated env variable FALCO_DRIVER_LOADER_OPTIONS to array, prevent
# shell expansion and use it as argument list for falco-driver-loader
read -a falco_driver_loader_option_arr <<< $FALCO_DRIVER_LOADER_OPTIONS
/usr/bin/falco-driver-loader "${falco_driver_loader_option_arr[@]}"
fi
exec "$@"

View File

@@ -1,4 +1,4 @@
FROM ubuntu:18.04 as ubuntu
FROM debian:12 as builder
ARG FALCO_VERSION
ARG VERSION_BUCKET=bin
@@ -20,7 +20,7 @@ RUN curl -L -o falco.tar.gz \
RUN sed -e 's/time_format_iso_8601: false/time_format_iso_8601: true/' < /falco/etc/falco/falco.yaml > /falco/etc/falco/falco.yaml.new \
&& mv /falco/etc/falco/falco.yaml.new /falco/etc/falco/falco.yaml
FROM debian:11-slim
FROM debian:12-slim
LABEL maintainer="cncf-falco-dev@lists.cncf.io"
LABEL org.opencontainers.image.source="https://github.com/falcosecurity/falco"
@@ -34,6 +34,6 @@ RUN apt-get -y update && apt-get -y install ca-certificates curl jq \
ENV HOST_ROOT /host
ENV HOME /root
COPY --from=ubuntu /falco /
COPY --from=builder /falco /
CMD ["/usr/bin/falco", "-o", "time_format_iso_8601=true"]

View File

@@ -0,0 +1,38 @@
FROM cgr.dev/chainguard/wolfi-base as builder
ARG FALCO_VERSION
ARG VERSION_BUCKET=bin
ENV FALCO_VERSION=${FALCO_VERSION}
ENV VERSION_BUCKET=${VERSION_BUCKET}
RUN apk update && apk add build-base gcc curl ca-certificates jq
WORKDIR /
RUN FALCO_VERSION_URLENCODED=$(echo -n ${FALCO_VERSION}|jq -sRr @uri) && \
curl -L -o falco.tar.gz \
https://download.falco.org/packages/${VERSION_BUCKET}/$(uname -m)/falco-${FALCO_VERSION_URLENCODED}-$(uname -m).tar.gz && \
tar -xvf falco.tar.gz && \
rm -f falco.tar.gz && \
mv falco-${FALCO_VERSION}-$(uname -m) falco && \
rm -rf /falco/usr/src/falco-* /falco/usr/bin/falco-driver-loader
RUN sed -e 's/time_format_iso_8601: false/time_format_iso_8601: true/' < /falco/etc/falco/falco.yaml > /falco/etc/falco/falco.yaml.new \
&& mv /falco/etc/falco/falco.yaml.new /falco/etc/falco/falco.yaml
FROM cgr.dev/chainguard/glibc-dynamic
LABEL maintainer="cncf-falco-dev@lists.cncf.io"
LABEL org.opencontainers.image.source="https://github.com/falcosecurity/falco"
LABEL usage="docker run -i -t --privileged -v /var/run/docker.sock:/host/var/run/docker.sock -v /dev:/host/dev -v /proc:/host/proc:ro --name NAME IMAGE"
# NOTE: for the "least privileged" use case, please refer to the official documentation
ENV HOST_ROOT /host
ENV HOME /root
USER root
COPY --from=builder /falco /
CMD ["/usr/bin/falco", "-o", "time_format_iso_8601=true"]

View File

@@ -39,6 +39,8 @@
# json_include_tags_property
# buffered_outputs
# outputs (throttling)
# rule_matching
# outputs_queue
# Falco outputs channels
# stdout_output
# syslog_output
@@ -134,6 +136,12 @@
# By arranging the order of files and rules thoughtfully, you can ensure that
# desired customizations and rule behaviors are prioritized and applied as
# intended.
#
# With Falco 0.36 and beyond, it's now possible to apply multiple rules that match
# the same event type, eliminating concerns about rule prioritization based on the
# "first match wins" principle. However, enabling the `all` matching option may result
# in a performance penalty. We recommend carefully testing this alternative setting
# before deploying it in production. Read more under the `rule_matching` configuration.
rules_file:
- /etc/falco/falco_rules.yaml
- /etc/falco/falco_rules.local.yaml
@@ -266,6 +274,9 @@ buffered_outputs: false
# [Stable] `outputs`
#
# [DEPRECATED]
# This config is deprecated and it will be removed in Falco 0.37
#
# A throttling mechanism, implemented as a token bucket, can be used to control
# the rate of Falco outputs. Each event source has its own rate limiter,
# ensuring that alerts from one source do not affect the throttling of others.
@@ -297,13 +308,47 @@ outputs:
# - `all`: Falco will continue checking conditions of rules even if a matching
# one was already found
#
# Rules conditions are evaluated in the order they are defined in the rulesfiles.
# Rules conditions are evaluated in the order they are defined in the rules files.
# For this reason, when using `first` as value, only the first defined rule will
# trigger, possibly shadowing other rules.
# In case `all` is used as value, rules still trigger in the order they were
# defined.
#
# Effectively, with this setting, it is now possible to apply multiple rules that match
# the same event type. This eliminates concerns about rule prioritization based on the
# "first match wins" principle. However, enabling the `all` matching option may result in
# a performance penalty. We recommend carefully testing this alternative setting before
# deploying it in production.
rule_matching: first
# [Experimental] `outputs_queue`
#
# Falco utilizes tbb::concurrent_bounded_queue for handling outputs, and this parameter
# allows you to customize the queue capacity. Please refer to the official documentation:
# https://oneapi-src.github.io/oneTBB/main/tbb_userguide/Concurrent_Queue_Classes.html.
# On a healthy system with optimized Falco rules, the queue should not fill up.
# If it does, it is most likely happening due to the entire event flow being too slow,
# indicating that the server is under heavy load.
#
# Lowering the number of items can prevent memory from steadily increasing until the OOM
# killer stops the Falco process. We provide recovery actions to self-limit or self-kill
# in order to handle this situation earlier, similar to how we expose the kernel buffer size
# as a parameter. However, it will not address the root cause of the event pipe not keeping up.
#
# `capacity`: the maximum number of items allowed in the queue is determined by this value.
# Setting the value to 0 (which is the default) is equivalent to keeping the queue unbounded.
# In other words, when this configuration is set to 0, the number of allowed items is effectively
# set to the largest possible long value, disabling this setting.
#
# `recovery`: strategy to follow when the queue becomes filled up. It applies only when the
# queue is bounded and there is still available system memory. In the case of an unbounded
# queue, if the available memory on the system is consumed, the Falco process would be
# OOM killed. The value `exit` is the default, `continue` does nothing special and `empty`
# empties the queue and then continues.
outputs_queue:
capacity: 0
recovery: exit
##########################
# Falco outputs channels #
@@ -359,6 +404,14 @@ http_output:
# Path to a folder that will be used as the CA certificate store. CA certificate need to be
# stored as indivitual PEM files in this directory.
ca_path: "/etc/ssl/certs"
# Tell Falco to use mTLS
mtls: false
# Path to the client cert.
client_cert: "/etc/ssl/certs/client.crt"
# Path to the client key.
client_key: "/etc/ssl/certs/client.key"
# Whether to echo server answers to stdout
echo: false
# [Stable] `program_output`
#
@@ -510,8 +563,8 @@ log_level: info
# operational logs. It allows you to specify the desired log level for the `libs`
# library specifically, providing more granular control over the logging
# behavior of the underlying components used by Falco. Only logs of a certain
# severity level or higher will be emitted. Supported levels: "emergency",
# "alert", "critical", "error", "warning", "notice", "info", "debug". It is not
# severity level or higher will be emitted. Supported levels: "fatal",
# "critical", "error", "warning", "notice", "info", "debug", "trace". It is not
# recommended for production use.
libs_logger:
enabled: false
@@ -613,7 +666,7 @@ syscall_event_drops:
max_burst: 1
simulate_drops: false
# [Experimental] `metrics`
# [Stable] `metrics`
#
# Generates "Falco internal: metrics snapshot" rule output when `priority=info` at minimum
# By selecting `output_file`, equivalent JSON output will be appended to a file.
@@ -736,6 +789,8 @@ syscall_event_drops:
metrics:
enabled: false
interval: 1h
# Typically, in production, you only use `output_rule` or `output_file`, but not both.
# However, if you have a very unique use case, you can use both together.
output_rule: true
# output_file: /tmp/falco_stats.jsonl
resource_utilization_enabled: true
@@ -811,7 +866,7 @@ syscall_buf_size_preset: 4
# visibility into the system.
syscall_drop_failed_exit: false
# [Experimental] `base_syscalls`, use with caution, read carefully
# [Stable] `base_syscalls`, use with caution, read carefully
#
# --- [Description]
#

View File

@@ -15,40 +15,42 @@
# limitations under the License.
#
# Systemd
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/scripts/systemd)
configure_file("${PROJECT_SOURCE_DIR}/scripts/systemd/falco-kmod-inject.service"
"${PROJECT_BINARY_DIR}/scripts/systemd" COPYONLY)
configure_file("${PROJECT_SOURCE_DIR}/scripts/systemd/falco-kmod.service"
"${PROJECT_BINARY_DIR}/scripts/systemd" COPYONLY)
configure_file("${PROJECT_SOURCE_DIR}/scripts/systemd/falco-bpf.service"
"${PROJECT_BINARY_DIR}/scripts/systemd" COPYONLY)
configure_file("${PROJECT_SOURCE_DIR}/scripts/systemd/falco-modern-bpf.service"
"${PROJECT_BINARY_DIR}/scripts/systemd" COPYONLY)
configure_file("${PROJECT_SOURCE_DIR}/scripts/systemd/falco-custom.service"
"${PROJECT_BINARY_DIR}/scripts/systemd" COPYONLY)
configure_file("${PROJECT_SOURCE_DIR}/scripts/systemd/falcoctl-artifact-follow.service"
"${PROJECT_BINARY_DIR}/scripts/systemd" COPYONLY)
# Debian
configure_file(debian/postinst.in debian/postinst COPYONLY)
configure_file(debian/postrm.in debian/postrm COPYONLY)
configure_file(debian/prerm.in debian/prerm COPYONLY)
# Rpm
configure_file(rpm/postinstall.in rpm/postinstall COPYONLY)
configure_file(rpm/postuninstall.in rpm/postuninstall COPYONLY)
configure_file(rpm/preuninstall.in rpm/preuninstall COPYONLY)
configure_file(falco-driver-loader falco-driver-loader @ONLY)
# Install Falcoctl config file
if(NOT DEFINED FALCOCTL_ETC_DIR)
set(FALCOCTL_ETC_DIR "${CMAKE_INSTALL_FULL_SYSCONFDIR}/falcoctl")
endif()
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/falcoctl/falcoctl.yaml DESTINATION "${FALCOCTL_ETC_DIR}" COMPONENT "${FALCO_COMPONENT_NAME}")
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
# Systemd
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/scripts/systemd)
configure_file("${PROJECT_SOURCE_DIR}/scripts/systemd/falco-kmod-inject.service"
"${PROJECT_BINARY_DIR}/scripts/systemd" COPYONLY)
configure_file("${PROJECT_SOURCE_DIR}/scripts/systemd/falco-kmod.service"
"${PROJECT_BINARY_DIR}/scripts/systemd" COPYONLY)
configure_file("${PROJECT_SOURCE_DIR}/scripts/systemd/falco-bpf.service"
"${PROJECT_BINARY_DIR}/scripts/systemd" COPYONLY)
configure_file("${PROJECT_SOURCE_DIR}/scripts/systemd/falco-modern-bpf.service"
"${PROJECT_BINARY_DIR}/scripts/systemd" COPYONLY)
configure_file("${PROJECT_SOURCE_DIR}/scripts/systemd/falco-custom.service"
"${PROJECT_BINARY_DIR}/scripts/systemd" COPYONLY)
configure_file("${PROJECT_SOURCE_DIR}/scripts/systemd/falcoctl-artifact-follow.service"
"${PROJECT_BINARY_DIR}/scripts/systemd" COPYONLY)
# Debian
configure_file(debian/postinst.in debian/postinst COPYONLY)
configure_file(debian/postrm.in debian/postrm COPYONLY)
configure_file(debian/prerm.in debian/prerm COPYONLY)
# Rpm
configure_file(rpm/postinstall.in rpm/postinstall COPYONLY)
configure_file(rpm/postuninstall.in rpm/postuninstall COPYONLY)
configure_file(rpm/preuninstall.in rpm/preuninstall COPYONLY)
# driver loader
configure_file(falco-driver-loader falco-driver-loader @ONLY)
install(PROGRAMS ${PROJECT_BINARY_DIR}/scripts/falco-driver-loader
DESTINATION ${FALCO_BIN_DIR} COMPONENT "${FALCO_COMPONENT_NAME}")
endif()
# Install Falcoctl config file
if (NOT WIN32 AND NOT APPLE AND NOT EMSCRIPTEN AND NOT MUSL_OPTIMIZED_BUILD)
if(NOT DEFINED FALCOCTL_ETC_DIR)
set(FALCOCTL_ETC_DIR "${CMAKE_INSTALL_FULL_SYSCONFDIR}/falcoctl")
endif()
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/falcoctl/falcoctl.yaml DESTINATION "${FALCOCTL_ETC_DIR}" COMPONENT "${FALCO_COMPONENT_NAME}")
endif()

View File

@@ -117,7 +117,9 @@ get_target_id() {
# Older RHEL distros
OS_ID=rhel
else
return 1
# No target id can be determinand
TARGET_ID="undetermined"
return
fi
# Overwrite the OS_ID if /etc/VERSION file is present.
@@ -163,7 +165,7 @@ get_target_id() {
then
ARCH_extra="-${BASH_REMATCH[1]}${BASH_REMATCH[2]}"
fi
if [[ $(uname -v) =~ ([0-9]+\.[0-9]+\.[0-9]+\-[0-9]+) ]];
if [[ ${DRIVER_KERNEL_VERSION} =~ ([0-9]+\.[0-9]+\.[0-9]+\-[0-9]+) ]];
then
KERNEL_RELEASE="${BASH_REMATCH[1]}${ARCH_extra}"
fi
@@ -187,9 +189,9 @@ get_target_id() {
# from the following `uname -v` result
# `#26~22.04.1-Ubuntu SMP Mon Apr 24 01:58:15 UTC 2023`
# we obtain the kernelversion`26~22.04.1`
if [[ $(uname -v) =~ (^\#[0-9]+\~[^-]*-Ubuntu .*$) ]];
if [[ ${DRIVER_KERNEL_VERSION} =~ (^\#[0-9]+\~[^-]*-Ubuntu .*$) ]];
then
KERNEL_VERSION=$(uname -v | sed 's/#\([^-\\ ]*\).*/\1/g')
KERNEL_VERSION=$(echo "${DRIVER_KERNEL_VERSION}" | sed 's/#\([^-\\ ]*\).*/\1/g')
fi
;;
("flatcar")
@@ -227,7 +229,6 @@ get_target_id() {
TARGET_ID=$(echo "${OS_ID}" | tr '[:upper:]' '[:lower:]')
;;
esac
return 0
}
flatcar_relocate_tools() {
@@ -258,7 +259,7 @@ flatcar_relocate_tools() {
load_kernel_module_compile() {
# Skip dkms on UEK hosts because it will always fail
if [[ $(uname -r) == *uek* ]]; then
if [[ ${DRIVER_KERNEL_RELEASE} == *uek* ]]; then
>&2 echo "Skipping because the dkms install always fail (on UEK hosts)"
return
fi
@@ -269,7 +270,7 @@ load_kernel_module_compile() {
fi
if [ "${TARGET_ID}" == "flatcar" ]; then
KERNEL_RELEASE=$(uname -r)
KERNEL_RELEASE=${DRIVER_KERNEL_RELEASE}
echo "* Flatcar detected (version ${VERSION_ID}); relocating kernel tools"
flatcar_relocate_tools
fi
@@ -343,9 +344,9 @@ load_kernel_module_download() {
print_clean_termination() {
echo
echo "[SUCCESS] Cleaning phase correctly terminated."
echo
echo
echo "================ Cleaning phase ================"
echo
echo
}
print_filename_components() {
@@ -355,10 +356,24 @@ print_filename_components() {
echo " - kernel version: ${KERNEL_VERSION}"
}
print_as_env_vars() {
echo "ARCH=\"${ARCH}\""
echo "KERNEL_RELEASE=\"${KERNEL_RELEASE}\""
echo "KERNEL_VERSION=\"${KERNEL_VERSION}\""
echo "ENABLE_COMPILE=\"${ENABLE_COMPILE}\""
echo "ENABLE_DOWNLOAD=\"${ENABLE_DOWNLOAD}\""
echo "TARGET_ID=\"${TARGET_ID}\""
echo "DRIVER=\"${DRIVER}\""
echo "DRIVERS_REPO=\"${DRIVERS_REPO}\""
echo "DRIVER_VERSION=\"${DRIVER_VERSION}\""
echo "DRIVER_NAME=\"${DRIVER_NAME}\""
echo "FALCO_VERSION=\"${FALCO_VERSION}\""
}
clean_kernel_module() {
echo
echo
echo "================ Cleaning phase ================"
echo
echo
if ! hash lsmod > /dev/null 2>&1; then
>&2 echo "This program requires lsmod."
@@ -401,7 +416,7 @@ clean_kernel_module() {
echo "[WARNING] '${KMOD_NAME}' module is still loaded, you could have incompatibility issues."
echo
fi
if ! hash dkms >/dev/null 2>&1; then
echo "- Skipping dkms remove (dkms not found)."
print_clean_termination
@@ -528,7 +543,7 @@ load_bpf_probe_compile() {
MINIKUBE_VERSION="$(cat "${HOST_ROOT}/etc/VERSION")"
echo "* Minikube detected (${MINIKUBE_VERSION}), using linux kernel sources for minikube kernel"
local kernel_version
kernel_version=$(uname -r)
kernel_version=${DRIVER_KERNEL_RELEASE}
local -r kernel_version_major=$(echo "${kernel_version}" | cut -d. -f1)
local -r kernel_version_minor=$(echo "${kernel_version}" | cut -d. -f2)
local -r kernel_version_patch=$(echo "${kernel_version}" | cut -d. -f3)
@@ -541,9 +556,9 @@ load_bpf_probe_compile() {
fi
if [ -n "${BPF_USE_LOCAL_KERNEL_SOURCES}" ]; then
local -r kernel_version_major=$(uname -r | cut -d. -f1)
local -r kernel_version=$(uname -r | cut -d- -f1)
KERNEL_EXTRA_VERSION="-$(uname -r | cut -d- -f2)"
local -r kernel_version_major=$(echo "${DRIVER_KERNEL_RELEASE}" | cut -d. -f1)
local -r kernel_version=$(echo "${DRIVER_KERNEL_RELEASE}" | cut -d- -f1)
KERNEL_EXTRA_VERSION="-$(echo "${DRIVER_KERNEL_RELEASE}" | cut -d- -f2)"
echo "* Using downloaded kernel sources for kernel version ${kernel_version}..."
@@ -666,13 +681,16 @@ print_usage() {
echo " --clean try to remove an already present driver installation"
echo " --compile try to compile the driver locally (default true)"
echo " --download try to download a prebuilt driver (default true)"
echo " --source-only skip execution and allow sourcing in another script"
echo " --source-only skip execution and allow sourcing in another script using `. falco-driver-loader`"
echo " --print-env skip execution and print env variables for other tools to consume"
echo ""
echo "Environment variables:"
echo " DRIVERS_REPO specify different URL(s) where to look for prebuilt Falco drivers (comma separated)"
echo " DRIVER_NAME specify a different name for the driver"
echo " DRIVER_INSECURE_DOWNLOAD whether you want to allow insecure downloads or not"
echo " DRIVER_CURL_OPTIONS specify additional options to be passed to curl command used to download Falco drivers"
echo " DRIVER_KERNEL_RELEASE specify the kernel release for which to download/build the driver in the same format used by 'uname -r' (e.g. '6.1.0-10-cloud-amd64')"
echo " DRIVER_KERNEL_VERSION specify the kernel version for which to download/build the driver in the same format used by 'uname -v' (e.g. '#1 SMP PREEMPT_DYNAMIC Debian 6.1.38-2 (2023-07-27)')"
echo ""
echo "Versions:"
echo " Falco version ${FALCO_VERSION}"
@@ -682,13 +700,16 @@ print_usage() {
ARCH=$(uname -m)
KERNEL_RELEASE=$(uname -r)
DRIVER_KERNEL_RELEASE=${DRIVER_KERNEL_RELEASE:-$(uname -r)}
KERNEL_RELEASE=${DRIVER_KERNEL_RELEASE}
if ! hash sed > /dev/null 2>&1; then
>&2 echo "This program requires sed"
exit 1
fi
KERNEL_VERSION=$(uname -v | sed 's/#\([[:digit:]]\+\).*/\1/')
DRIVER_KERNEL_VERSION=${DRIVER_KERNEL_VERSION:-$(uname -v)}
KERNEL_VERSION=$(echo "${DRIVER_KERNEL_VERSION}" | sed 's/#\([[:digit:]]\+\).*/\1/')
DRIVERS_REPO=${DRIVERS_REPO:-"@DRIVERS_REPO@"}
@@ -709,7 +730,8 @@ DRIVER_VERSION=${DRIVER_VERSION:-"@DRIVER_VERSION@"}
DRIVER_NAME=${DRIVER_NAME:-"@DRIVER_NAME@"}
FALCO_VERSION="@FALCO_VERSION@"
TARGET_ID="placeholder" # when no target id can be fetched, we try to build the driver from source anyway, using a placeholder name
TARGET_ID=
get_target_id
DRIVER="module"
if [ -v FALCO_BPF_PROBE ]; then
@@ -724,6 +746,7 @@ ENABLE_DOWNLOAD=
clean=
has_args=
has_opts=
print_env=
source_only=
while test $# -gt 0; do
case "$1" in
@@ -760,6 +783,10 @@ while test $# -gt 0; do
source_only="true"
shift
;;
--print-env)
print_env="true"
shift
;;
--*)
>&2 echo "Unknown option: $1"
print_usage
@@ -778,55 +805,61 @@ if [ -z "$has_opts" ]; then
ENABLE_DOWNLOAD="yes"
fi
if [ -z "$source_only" ]; then
echo "* Running falco-driver-loader for: falco version=${FALCO_VERSION}, driver version=${DRIVER_VERSION}, arch=${ARCH}, kernel release=${KERNEL_RELEASE}, kernel version=${KERNEL_VERSION}"
if [ -n "$source_only" ]; then
# Return or exit, depending if we've been sourced.
(return 0 2>/dev/null) && return || exit 0
fi
if [ "$(id -u)" != 0 ]; then
>&2 echo "This program must be run as root (or with sudo)"
if [ -n "$print_env" ]; then
print_as_env_vars
exit 0
fi
echo "* Running falco-driver-loader for: falco version=${FALCO_VERSION}, driver version=${DRIVER_VERSION}, arch=${ARCH}, kernel release=${KERNEL_RELEASE}, kernel version=${KERNEL_VERSION}"
if [ "$(id -u)" != 0 ]; then
>&2 echo "This program must be run as root (or with sudo)"
exit 1
fi
if [ "$TARGET_ID" = "undetermined" ]; then
if [ -n "$ENABLE_COMPILE" ]; then
ENABLE_DOWNLOAD=
>&2 echo "Detected an unsupported target system, please get in touch with the Falco community. Trying to compile anyway."
else
>&2 echo "Detected an unsupported target system, please get in touch with the Falco community."
exit 1
fi
fi
if [ -n "$clean" ]; then
if [ -n "$has_opts" ]; then
>&2 echo "Cannot use --clean with other options"
exit 1
fi
get_target_id
res=$?
if [ $res != 0 ]; then
if [ -n "$ENABLE_COMPILE" ]; then
ENABLE_DOWNLOAD=
>&2 echo "Detected an unsupported target system, please get in touch with the Falco community. Trying to compile anyway."
else
>&2 echo "Detected an unsupported target system, please get in touch with the Falco community."
exit 1
fi
echo "* Running falco-driver-loader with: driver=$DRIVER, clean=yes"
case $DRIVER in
module)
clean_kernel_module
;;
bpf)
>&2 echo "--clean not supported for driver=bpf"
exit 1
esac
else
if ! hash curl > /dev/null 2>&1; then
>&2 echo "This program requires curl"
exit 1
fi
if [ -n "$clean" ]; then
if [ -n "$has_opts" ]; then
>&2 echo "Cannot use --clean with other options"
exit 1
fi
echo "* Running falco-driver-loader with: driver=$DRIVER, clean=yes"
case $DRIVER in
echo "* Running falco-driver-loader with: driver=$DRIVER, compile=${ENABLE_COMPILE:-"no"}, download=${ENABLE_DOWNLOAD:-"no"}"
case $DRIVER in
module)
clean_kernel_module
load_kernel_module
;;
bpf)
>&2 echo "--clean not supported for driver=bpf"
exit 1
esac
else
if ! hash curl > /dev/null 2>&1; then
>&2 echo "This program requires curl"
exit 1
fi
echo "* Running falco-driver-loader with: driver=$DRIVER, compile=${ENABLE_COMPILE:-"no"}, download=${ENABLE_DOWNLOAD:-"no"}"
case $DRIVER in
module)
load_kernel_module
;;
bpf)
load_bpf_probe
;;
esac
fi
load_bpf_probe
;;
esac
fi

View File

@@ -8,7 +8,8 @@ Wants=falcoctl-artifact-follow.service
Type=simple
User=root
Environment=FALCO_BPF_PROBE=
ExecStart=/usr/bin/falco --pidfile=/var/run/falco.pid
ExecStart=/usr/bin/falco
ExecReload=kill -1 $MAINPID
UMask=0077
TimeoutSec=30
RestartSec=15s

View File

@@ -7,7 +7,8 @@ Wants=falcoctl-artifact-follow.service
[Service]
Type=simple
User=%u
ExecStart=/usr/bin/falco --pidfile=/var/run/falco.pid
ExecStart=/usr/bin/falco
ExecReload=kill -1 $MAINPID
UMask=0077
TimeoutSec=30
RestartSec=15s

View File

@@ -9,7 +9,8 @@ Wants=falcoctl-artifact-follow.service
[Service]
Type=simple
User=root
ExecStart=/usr/bin/falco --pidfile=/var/run/falco.pid
ExecStart=/usr/bin/falco
ExecReload=kill -1 $MAINPID
UMask=0077
TimeoutSec=30
RestartSec=15s

View File

@@ -7,7 +7,8 @@ Wants=falcoctl-artifact-follow.service
[Service]
Type=simple
User=root
ExecStart=/usr/bin/falco --pidfile=/var/run/falco.pid --modern-bpf
ExecStart=/usr/bin/falco --modern-bpf
ExecReload=kill -1 $MAINPID
UMask=0077
TimeoutSec=30
RestartSec=15s

View File

@@ -28,9 +28,17 @@ file(GLOB_RECURSE FALCO_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/falco/*.cpp)
set(FALCO_UNIT_TESTS_SOURCES
"${ENGINE_TESTS}"
"${FALCO_TESTS}"
falco/test_configuration.cpp
falco/app/actions/test_select_event_sources.cpp
)
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
list(APPEND FALCO_UNIT_TESTS_SOURCES
falco/test_atomic_signal_handler.cpp
falco/app/actions/test_configure_interesting_sets.cpp
falco/app/actions/test_configure_syscall_buffer_num.cpp)
endif()
set(FALCO_UNIT_TESTS_INCLUDES
PRIVATE
${CMAKE_SOURCE_DIR}/userspace
@@ -62,3 +70,10 @@ add_executable(falco_unit_tests ${FALCO_UNIT_TESTS_SOURCES})
target_include_directories(falco_unit_tests ${FALCO_UNIT_TESTS_INCLUDES})
target_link_libraries(falco_unit_tests ${FALCO_UNIT_TESTS_LIBRARIES})
add_dependencies(falco_unit_tests ${FALCO_UNIT_TESTS_DEPENDENCIES})
if (EMSCRIPTEN)
target_compile_options(falco_unit_tests PRIVATE "-sDISABLE_EXCEPTION_CATCHING=0")
target_link_options(falco_unit_tests PRIVATE "-sDISABLE_EXCEPTION_CATCHING=0")
target_link_options(falco_unit_tests PRIVATE "-sALLOW_MEMORY_GROWTH=1")
target_link_options(falco_unit_tests PRIVATE "-sEXPORTED_FUNCTIONS=['_main','_htons','_ntohs']")
endif()

View File

@@ -45,8 +45,8 @@ TEST(FalcoUtils, parse_prometheus_interval)
ASSERT_EQ(falco::utils::parse_prometheus_interval("1m"), 60000UL);
ASSERT_EQ(falco::utils::parse_prometheus_interval("1h"), 3600000UL);
ASSERT_EQ(falco::utils::parse_prometheus_interval("1d"), 86400000UL);
ASSERT_EQ(falco::utils::parse_prometheus_interval("1w"), 604800000UL);
ASSERT_EQ(falco::utils::parse_prometheus_interval("1y"), 31536000000UL);
ASSERT_EQ(falco::utils::parse_prometheus_interval("1w"), 604800000UL);
ASSERT_EQ(falco::utils::parse_prometheus_interval("1y"), (unsigned long)31536000000UL);
ASSERT_EQ(falco::utils::parse_prometheus_interval("300ms"), 300UL);
ASSERT_EQ(falco::utils::parse_prometheus_interval("255s"), 255000UL);
@@ -57,14 +57,17 @@ TEST(FalcoUtils, parse_prometheus_interval)
/* Test matrix for concatenated time interval examples. */
ASSERT_EQ(falco::utils::parse_prometheus_interval("1h3m2s1ms"), 3600000UL + 3 * 60000UL + 2 * 1000UL + 1UL);
ASSERT_EQ(falco::utils::parse_prometheus_interval("1y1w1d1h1m1s1ms"), 31536000000UL + 604800000UL + 86400000UL + 3600000UL + 60000UL + 1000UL + 1UL);
ASSERT_EQ(falco::utils::parse_prometheus_interval("1y1w1d1h1m1s1ms"),(unsigned long) 31536000000UL + 604800000UL + 86400000UL + 3600000UL + 60000UL + 1000UL + 1UL);
ASSERT_EQ(falco::utils::parse_prometheus_interval("2h5m"), 2 * 3600000UL + 5 * 60000UL);
ASSERT_EQ(falco::utils::parse_prometheus_interval("2h 5m"), 2 * 3600000UL + 5 * 60000UL);
ASSERT_EQ(falco::utils::parse_prometheus_interval("200"), 200UL);
/* Invalid, non prometheus compliant time ordering will result in 0ms. */
ASSERT_EQ(falco::utils::parse_prometheus_interval("1ms1y"), 0UL);
ASSERT_EQ(falco::utils::parse_prometheus_interval("1t1y"), 0UL);
ASSERT_EQ(falco::utils::parse_prometheus_interval("1t"), 0UL);
/* Deprecated option to pass a numeric value in ms without prometheus compliant time unit,
* will result in 0ms and as a result the end user will receive an error warning.
*/
ASSERT_EQ(falco::utils::parse_prometheus_interval("200"), 0UL);
}

View File

@@ -88,16 +88,88 @@ TEST(Configuration, modify_yaml_fields)
{
std::string key = "base_value.subvalue.subvalue2.boolean";
yaml_helper conf;
/* Get original value */
conf.load_from_string(sample_yaml);
ASSERT_EQ(conf.get_scalar<bool>(key, false), true);
/* Modify the original value */
conf.set_scalar<bool>(key, false);
ASSERT_EQ(conf.get_scalar<bool>(key, true), false);
/* Modify it again */
conf.set_scalar<bool>(key, true);
ASSERT_EQ(conf.get_scalar<bool>(key, false), true);
}
TEST(Configuration, configuration_environment_variables)
{
// Set an environment variable for testing purposes
std::string env_var_value = "envVarValue";
std::string env_var_name = "ENV_VAR";
std::string default_value = "default";
setenv(env_var_name.c_str(), env_var_value.c_str(), 1);
yaml_helper conf;
std::string sample_yaml =
"base_value:\n"
" id: $ENV_VAR\n"
" name: '${ENV_VAR}'\n"
" string: my_string\n"
" invalid: $${ENV_VAR}\n"
" invalid_env: $$ENV_VAR\n"
" escaped: \"${ENV_VAR}\"\n"
" subvalue:\n"
" subvalue2:\n"
" boolean: ${UNSED_XX_X_X_VAR}\n"
"base_value_2:\n"
" sample_list:\n"
" - ${ENV_VAR}\n"
" - ' ${ENV_VAR}'\n"
" - $UNSED_XX_X_X_VAR\n";
conf.load_from_string(sample_yaml);
/* Check if the base values are defined */
ASSERT_TRUE(conf.is_defined("base_value"));
ASSERT_TRUE(conf.is_defined("base_value_2"));
ASSERT_FALSE(conf.is_defined("unknown_base_value"));
/* Test fetching of a regular string without any environment variable */
std::string base_value_string = conf.get_scalar<std::string>("base_value.string", default_value);
ASSERT_EQ(base_value_string, "my_string");
/* Test fetching of escaped environment variable format. Should return the string as-is after stripping the leading `$` */
std::string base_value_invalid = conf.get_scalar<std::string>("base_value.invalid", default_value);
ASSERT_EQ(base_value_invalid, "${ENV_VAR}");
/* Test fetching of invalid escaped environment variable format. Should return the string as-is */
std::string base_value_invalid_env = conf.get_scalar<std::string>("base_value.invalid_env", default_value);
ASSERT_EQ(base_value_invalid_env, "$$ENV_VAR");
/* Test fetching of strings that contain environment variables */
std::string base_value_id = conf.get_scalar<std::string>("base_value.id", default_value);
ASSERT_EQ(base_value_id, "$ENV_VAR"); // Does not follow the `${VAR}` format, so it should be treated as a regular string
std::string base_value_name = conf.get_scalar<std::string>("base_value.name", default_value);
ASSERT_EQ(base_value_name, env_var_value); // Proper environment variable format
std::string base_value_escaped = conf.get_scalar<std::string>("base_value.escaped", default_value);
ASSERT_EQ(base_value_escaped, env_var_value); // Environment variable within quotes
/* Test fetching of an undefined environment variable. Expected to return the default value.*/
std::string unknown_boolean = conf.get_scalar<std::string>("base_value.subvalue.subvalue2.boolean", default_value);
ASSERT_EQ(unknown_boolean, default_value);
/* Test fetching of environment variables from a list */
std::string base_value_2_list_0 = conf.get_scalar<std::string>("base_value_2.sample_list[0]", default_value);
ASSERT_EQ(base_value_2_list_0, env_var_value); // Proper environment variable format
std::string base_value_2_list_1 = conf.get_scalar<std::string>("base_value_2.sample_list[1]", default_value);
ASSERT_EQ(base_value_2_list_1, " ${ENV_VAR}"); // Environment variable preceded by a space, hence treated as a regular string
std::string base_value_2_list_2 = conf.get_scalar<std::string>("base_value_2.sample_list[2]", default_value);
ASSERT_EQ(base_value_2_list_2, "$UNSED_XX_X_X_VAR"); // Does not follow the `${VAR}` format, so should be treated as a regular string
/* Clear the set environment variable after testing */
unsetenv(env_var_name.c_str());
}

View File

@@ -29,6 +29,10 @@ set(FALCO_ENGINE_SOURCE_FILES
add_library(falco_engine STATIC ${FALCO_ENGINE_SOURCE_FILES})
if (EMSCRIPTEN)
target_compile_options(falco_engine PRIVATE "-sDISABLE_EXCEPTION_CATCHING=0")
endif()
add_dependencies(falco_engine yamlcpp njson)
if(MINIMAL_BUILD)

View File

@@ -32,6 +32,12 @@ static std::vector<std::string> rule_matching_names = {
"all"
};
static std::vector<std::string> outputs_queue_recovery_names = {
"continue",
"exit",
"empty",
};
bool falco_common::parse_priority(std::string v, priority_type& out)
{
for (size_t i = 0; i < priority_names.size(); i++)
@@ -59,6 +65,19 @@ falco_common::priority_type falco_common::parse_priority(std::string v)
return out;
}
bool falco_common::parse_queue_recovery(std::string v, outputs_queue_recovery_type& out)
{
for (size_t i = 0; i < outputs_queue_recovery_names.size(); i++)
{
if (!strcasecmp(v.c_str(), outputs_queue_recovery_names[i].c_str()))
{
out = (outputs_queue_recovery_type) i;
return true;
}
}
return false;
}
bool falco_common::format_priority(priority_type v, std::string& out, bool shortfmt)
{
if ((size_t) v < priority_names.size())

View File

@@ -21,6 +21,12 @@ limitations under the License.
#include <mutex>
#include <sinsp.h>
//
// equivalent to an "unbounded queue" in TBB terms or largest long value
// https://github.com/oneapi-src/oneTBB/blob/b2474bfc636937052d05daf8b3f4d6b76e20273a/include/oneapi/tbb/concurrent_queue.h#L554
//
#define DEFAULT_OUTPUTS_QUEUE_CAPACITY_UNBOUNDED_MAX_LONG_VALUE std::ptrdiff_t(~size_t(0) / 2)
//
// Most falco_* classes can throw exceptions. Unless directly related
// to low-level failures like inability to open file, etc, they will
@@ -52,6 +58,13 @@ struct falco_exception : std::exception
namespace falco_common
{
enum outputs_queue_recovery_type {
RECOVERY_CONTINUE = 0, /* outputs_queue_capacity recovery strategy of continuing on. */
RECOVERY_EXIT = 1, /* outputs_queue_capacity recovery strategy of exiting, self OOM kill. */
RECOVERY_EMPTY = 2, /* outputs_queue_capacity recovery strategy of emptying queue then continuing. */
};
const std::string syscall_source = sinsp_syscall_event_source_name;
// Same as numbers/indices into the above vector
@@ -69,6 +82,7 @@ namespace falco_common
bool parse_priority(std::string v, priority_type& out);
priority_type parse_priority(std::string v);
bool parse_queue_recovery(std::string v, outputs_queue_recovery_type& out);
bool format_priority(priority_type v, std::string& out, bool shortfmt=false);
std::string format_priority(priority_type v, bool shortfmt=false);

View File

@@ -246,7 +246,13 @@ std::unique_ptr<load_result> falco_engine::load_rules_file(const std::string &ru
res->add_error(load_result::LOAD_ERR_FILE_READ, e.what(), ctx);
// Old gcc versions (e.g. 4.8.3) won't allow move elision but newer versions
// (e.g. 10.2.1) would complain about the redundant move.
#if __GNUC__ > 4
return res;
#else
return std::move(res);
#endif
}
return load_rules(rules_content, rules_filename);
@@ -562,12 +568,12 @@ void falco_engine::describe_rule(std::string *rule, bool json) const
output["lists"] = lists_array;
json_str = writer.write(output);
}
}
else
{
// build json information for just the specified rule
auto ri = m_rule_collector.rules().at(*rule);
if(ri == nullptr)
if(ri == nullptr || ri->unknown_source)
{
throw falco_exception("Rule \"" + *rule + "\" is not loaded");
}

View File

@@ -15,12 +15,12 @@ limitations under the License.
*/
// The version of this Falco engine.
#define FALCO_ENGINE_VERSION (22)
#define FALCO_ENGINE_VERSION (26)
// This is the result of running the following command:
// FALCO="falco -c ./falco.yaml"
// echo $($FALCO --version | grep 'Engine:' | awk '{print $2}') $(echo $($FALCO --version | grep 'Schema version:' | awk '{print $3}') $($FALCO --list --markdown | grep '^`' | sort) $($FALCO --list-syscall-events | sort) | sha256sum)
// echo $($FALCO --version | grep 'Engine:' | awk '{print $2}') $(echo $($FALCO --version | grep 'Schema version:' | awk '{print $3}') $($FALCO --list --markdown | grep '^`' | sort) $($FALCO --list-events | sort) | sha256sum)
// It represents the fields supported by this version of Falco,
// the event types, and the underlying driverevent schema. It's used to
// detetect changes in engine version in our CI jobs.
#define FALCO_ENGINE_CHECKSUM "41dc03aebd3dd09e1aaaa1bb25055b65902c7c61c180cb9486d1d9850d18d67b"
#define FALCO_ENGINE_CHECKSUM "98c6e665031b95c666a9ab02d5470e7008e8636bf02f4cc410912005b90dff5c"

View File

@@ -62,7 +62,7 @@ static const std::string warning_codes[] = {
"LOAD_UNKNOWN_SOURCE",
"LOAD_UNSAFE_NA_CHECK",
"LOAD_NO_EVTTYPE",
"LOAD_UNKNOWN_FIELD",
"LOAD_UNKNOWN_FILTER",
"LOAD_UNUSED_MACRO",
"LOAD_UNUSED_LIST",
"LOAD_UNKNOWN_ITEM"
@@ -77,7 +77,7 @@ static const std::string warning_strings[] = {
"Unknown event source",
"Unsafe <NA> comparison in condition",
"Condition has no event-type restriction",
"Unknown field in condition",
"Unknown field or event-type in condition or output",
"Unused macro",
"Unused list",
"Unknown rules file item"
@@ -92,7 +92,7 @@ static const std::string warning_descs[] = {
"A rule has a unknown event source. This can occur when reading rules content without having a corresponding plugin loaded, etc. The rule will be silently ignored.",
"Comparing a field value with <NA> is unsafe and can lead to unpredictable behavior of the rule condition. If you need to check for the existence of a field, consider using the 'exists' operator instead.",
"A rule condition matches too many evt.type values. This has a significant performance penalty. Make the condition more specific by adding an evt.type field or further restricting the number of evt.type values in the condition.",
"A rule condition refers to a field that does not exist. This is normally an error, but if a rule has a skip-if-unknown-filter property, the error is downgraded to a warning.",
"A rule condition or output refers to a field or evt.type that does not exist. This is normally an error, but if a rule has a skip-if-unknown-filter property, the error is downgraded to a warning.",
"A macro is defined in the rules content but is not used by any other macro or rule.",
"A list is defined in the rules content but is not used by any other list, macro, or rule.",
"An unknown top-level object is in the rules content. It will be ignored."

View File

@@ -50,7 +50,7 @@ public:
LOAD_UNKNOWN_SOURCE = 0,
LOAD_UNSAFE_NA_CHECK,
LOAD_NO_EVTTYPE,
LOAD_UNKNOWN_FIELD,
LOAD_UNKNOWN_FILTER,
LOAD_UNUSED_MACRO,
LOAD_UNUSED_LIST,
LOAD_UNKNOWN_ITEM

View File

@@ -62,63 +62,51 @@ uint64_t parse_prometheus_interval(std::string interval_str)
if(!interval_str.empty())
{
/* Option 1: Passing interval directly in ms. Will be deprecated in the future. */
if(std::all_of(interval_str.begin(), interval_str.end(), ::isdigit))
re2::StringPiece input(interval_str);
std::string args[14];
re2::RE2::Arg arg0(&args[0]);
re2::RE2::Arg arg1(&args[1]);
re2::RE2::Arg arg2(&args[2]);
re2::RE2::Arg arg3(&args[3]);
re2::RE2::Arg arg4(&args[4]);
re2::RE2::Arg arg5(&args[5]);
re2::RE2::Arg arg6(&args[6]);
re2::RE2::Arg arg7(&args[7]);
re2::RE2::Arg arg8(&args[8]);
re2::RE2::Arg arg9(&args[9]);
re2::RE2::Arg arg10(&args[10]);
re2::RE2::Arg arg11(&args[11]);
re2::RE2::Arg arg12(&args[12]);
re2::RE2::Arg arg13(&args[13]);
const re2::RE2::Arg* const matches[14] = {&arg0, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7, &arg8, &arg9, &arg10, &arg11, &arg12, &arg13};
const std::map<std::string, int>& named_groups = s_rgx_prometheus_time_duration.NamedCapturingGroups();
int num_groups = s_rgx_prometheus_time_duration.NumberOfCapturingGroups();
re2::RE2::FullMatchN(input, s_rgx_prometheus_time_duration, matches, num_groups);
static const char* all_prometheus_units[7] = {
PROMETHEUS_UNIT_Y, PROMETHEUS_UNIT_W, PROMETHEUS_UNIT_D, PROMETHEUS_UNIT_H,
PROMETHEUS_UNIT_M, PROMETHEUS_UNIT_S, PROMETHEUS_UNIT_MS };
static const uint64_t all_prometheus_time_conversions[7] = {
ONE_YEAR_TO_MS, ONE_WEEK_TO_MS, ONE_DAY_TO_MS, ONE_HOUR_TO_MS,
ONE_MINUTE_TO_MS, ONE_SECOND_TO_MS, ONE_MS_TO_MS };
for(size_t i = 0; i < sizeof(all_prometheus_units) / sizeof(const char*); i++)
{
/* todo: deprecate for Falco 0.36. */
interval = std::stoull(interval_str, nullptr, 0);
}
/* Option 2: Passing a Prometheus compliant time duration.
* https://prometheus.io/docs/prometheus/latest/querying/basics/#time-durations
*/
else
{
re2::StringPiece input(interval_str);
std::string args[14];
re2::RE2::Arg arg0(&args[0]);
re2::RE2::Arg arg1(&args[1]);
re2::RE2::Arg arg2(&args[2]);
re2::RE2::Arg arg3(&args[3]);
re2::RE2::Arg arg4(&args[4]);
re2::RE2::Arg arg5(&args[5]);
re2::RE2::Arg arg6(&args[6]);
re2::RE2::Arg arg7(&args[7]);
re2::RE2::Arg arg8(&args[8]);
re2::RE2::Arg arg9(&args[9]);
re2::RE2::Arg arg10(&args[10]);
re2::RE2::Arg arg11(&args[11]);
re2::RE2::Arg arg12(&args[12]);
re2::RE2::Arg arg13(&args[13]);
const re2::RE2::Arg* const matches[14] = {&arg0, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7, &arg8, &arg9, &arg10, &arg11, &arg12, &arg13};
const std::map<std::string, int>& named_groups = s_rgx_prometheus_time_duration.NamedCapturingGroups();
int num_groups = s_rgx_prometheus_time_duration.NumberOfCapturingGroups();
re2::RE2::FullMatchN(input, s_rgx_prometheus_time_duration, matches, num_groups);
static const char* all_prometheus_units[7] = {
PROMETHEUS_UNIT_Y, PROMETHEUS_UNIT_W, PROMETHEUS_UNIT_D, PROMETHEUS_UNIT_H,
PROMETHEUS_UNIT_M, PROMETHEUS_UNIT_S, PROMETHEUS_UNIT_MS };
static const uint64_t all_prometheus_time_conversions[7] = {
ONE_YEAR_TO_MS, ONE_WEEK_TO_MS, ONE_DAY_TO_MS, ONE_HOUR_TO_MS,
ONE_MINUTE_TO_MS, ONE_SECOND_TO_MS, ONE_MS_TO_MS };
for(size_t i = 0; i < sizeof(all_prometheus_units) / sizeof(const char*); i++)
std::string cur_interval_str;
uint64_t cur_interval = 0;
const auto &group_it = named_groups.find(all_prometheus_units[i]);
if(group_it != named_groups.end())
{
std::string cur_interval_str;
uint64_t cur_interval = 0;
const auto &group_it = named_groups.find(all_prometheus_units[i]);
if(group_it != named_groups.end())
cur_interval_str = args[group_it->second - 1];
if(!cur_interval_str.empty())
{
cur_interval_str = args[group_it->second - 1];
if(!cur_interval_str.empty())
{
cur_interval = std::stoull(cur_interval_str, nullptr, 0);
}
if(cur_interval > 0)
{
interval += cur_interval * all_prometheus_time_conversions[i];
}
cur_interval = std::stoull(cur_interval_str, nullptr, 0);
}
if(cur_interval > 0)
{
interval += cur_interval * all_prometheus_time_conversions[i];
}
}
}

View File

@@ -16,7 +16,6 @@ limitations under the License.
#pragma once
#include <map>
#include <string>
#include <vector>
#include <unordered_map>

View File

@@ -547,8 +547,8 @@ rule_loader::rule_exception_info::rule_exception_info(context &ctx)
rule_loader::rule_info::rule_info(context &ctx)
: ctx(ctx), cond_ctx(ctx), output_ctx(ctx), index(0), visibility(0),
priority(falco_common::PRIORITY_DEBUG), enabled(true),
warn_evttypes(true), skip_if_unknown_filter(false)
unknown_source(false), priority(falco_common::PRIORITY_DEBUG),
enabled(true), warn_evttypes(true), skip_if_unknown_filter(false)
{
}

View File

@@ -449,6 +449,7 @@ namespace rule_loader
context output_ctx;
size_t index;
size_t visibility;
bool unknown_source;
std::string name;
std::string cond;
std::string source;

View File

@@ -54,7 +54,7 @@ static inline void append_info(T* prev, T& info, uint32_t id)
}
static void validate_exception_info(
const falco_source& source,
const falco_source* source,
rule_loader::rule_exception_info &ex)
{
if (ex.fields.is_list)
@@ -76,11 +76,14 @@ static void validate_exception_info(
std::string("'") + v.item + "' is not a supported comparison operator",
ex.ctx);
}
for (auto &v : ex.fields.items)
if (source)
{
THROW(!source.is_field_defined(v.item),
std::string("'") + v.item + "' is not a supported filter field",
ex.ctx);
for (auto &v : ex.fields.items)
{
THROW(!source->is_field_defined(v.item),
std::string("'") + v.item + "' is not a supported filter field",
ex.ctx);
}
}
}
else
@@ -96,9 +99,12 @@ static void validate_exception_info(
THROW((ex.comps.item != "in" && ex.comps.item != "pmatch" && ex.comps.item != "intersects"),
"When fields is a single value, comps must be one of (in, pmatch, intersects)",
ex.ctx);
THROW(!source.is_field_defined(ex.fields.item),
std::string("'") + ex.fields.item + "' is not a supported filter field",
ex.ctx);
if (source)
{
THROW(!source->is_field_defined(ex.fields.item),
std::string("'") + ex.fields.item + "' is not a supported filter field",
ex.ctx);
}
}
}
@@ -200,26 +206,25 @@ void rule_loader::collector::append(configuration& cfg, macro_info& info)
void rule_loader::collector::define(configuration& cfg, rule_info& info)
{
auto prev = m_rule_infos.at(info.name);
THROW(prev && prev->source != info.source,
"Rule has been re-defined with a different source",
info.ctx);
auto source = cfg.sources.at(info.source);
if (!source)
{
info.unknown_source = true;
cfg.res->add_warning(falco::load_result::LOAD_UNKNOWN_SOURCE,
"Unknown source " + info.source + ", skipping",
info.ctx);
return;
}
auto prev = m_rule_infos.at(info.name);
THROW(prev && prev->source != info.source,
"Rule has been re-defined with a different source",
info.ctx);
for (auto &ex : info.exceptions)
{
THROW(!ex.fields.is_valid(),
"Rule exception item must have fields property with a list of fields",
ex.ctx);
validate_exception_info(*source, ex);
"Rule exception item must have fields property with a list of fields",
ex.ctx);
validate_exception_info(source, ex);
}
define_info(m_rule_infos, info, m_cur_index++);
@@ -236,11 +241,17 @@ void rule_loader::collector::append(configuration& cfg, rule_info& info)
"Appended rule must have exceptions or condition property",
info.ctx);
auto source = cfg.sources.at(prev->source);
// note: this is not supposed to happen
THROW(!source,
std::string("Unknown source ") + prev->source,
info.ctx);
// note: source can be nullptr in case we've collected a
// rule for which the source is unknown
falco_source* source = nullptr;
if (!prev->unknown_source)
{
// note: if the source is not unknown, this should not return nullptr
source = cfg.sources.at(prev->source);
THROW(!source,
std::string("Unknown source ") + prev->source,
info.ctx);
}
if (!info.cond.empty())
{
@@ -261,7 +272,7 @@ void rule_loader::collector::append(configuration& cfg, rule_info& info)
THROW(ex.values.empty(),
"Rule exception must have values property with a list of values",
ex.ctx);
validate_exception_info(*source, ex);
validate_exception_info(source, ex);
prev->exceptions.push_back(ex);
}
else

View File

@@ -28,7 +28,7 @@ limitations under the License.
#define THROW(cond, err, ctx) { if ((cond)) { throw rule_loader::rule_load_exception(falco::load_result::LOAD_ERR_VALIDATE, (err), (ctx)); } }
static std::string s_container_info_fmt = "%container.info";
static std::string s_default_extra_fmt = "%container.name (id=%container.id)";
static std::string s_default_extra_fmt = "container_id=%container.id container_name=%container.name";
using namespace libsinsp::filter;
@@ -375,6 +375,12 @@ void rule_loader::compiler::compile_macros_infos(
}
}
static bool err_is_unknown_type_or_field(const std::string& err)
{
return err.find("nonexistent field") != std::string::npos
|| err.find("invalid formatting token") != std::string::npos
|| err.find("unknown event type") != std::string::npos;
}
void rule_loader::compiler::compile_rule_infos(
configuration& cfg,
@@ -388,17 +394,22 @@ void rule_loader::compiler::compile_rule_infos(
filter_warning_resolver warn_resolver;
for (auto &r : col.rules())
{
// skip the rule if it has an unknown source
if (r.unknown_source)
{
continue;
}
// skip the rule if below the minimum priority
if (r.priority > cfg.min_priority)
{
continue;
}
// note: this should not be nullptr if the source is not unknown
auto source = cfg.sources.at(r.source);
// note: this is not supposed to happen
THROW(!source,
std::string("Unknown source ") + r.source,
std::string("Unknown source at compile-time") + r.source,
r.ctx);
// build filter AST by parsing the condition, building exceptions,
@@ -433,6 +444,14 @@ void rule_loader::compiler::compile_rule_infos(
if(!is_format_valid(*cfg.sources.at(r.source), rule.output, err))
{
if (err_is_unknown_type_or_field(err) && r.skip_if_unknown_filter)
{
cfg.res->add_warning(
falco::load_result::load_result::LOAD_UNKNOWN_FILTER,
err,
r.output_ctx);
continue;
}
throw rule_load_exception(
falco::load_result::load_result::LOAD_ERR_COMPILE_OUTPUT,
err,
@@ -463,25 +482,20 @@ void rule_loader::compiler::compile_rule_infos(
// skip_if_unknown_filter is true
std::string err = e.what();
if (err.find("nonexistent field") != std::string::npos &&
r.skip_if_unknown_filter)
if (err_is_unknown_type_or_field(err) && r.skip_if_unknown_filter)
{
cfg.res->add_warning(
falco::load_result::load_result::LOAD_UNKNOWN_FIELD,
e.what(),
falco::load_result::load_result::LOAD_UNKNOWN_FILTER,
err,
r.cond_ctx);
continue;
}
else
{
rule_loader::context ctx(compiler.get_pos(),
condition,
r.cond_ctx);
throw rule_loader::rule_load_exception(
falco::load_result::load_result::LOAD_ERR_COMPILE_CONDITION,
e.what(),
ctx);
}
rule_loader::context ctx(compiler.get_pos(), condition, r.cond_ctx);
throw rule_loader::rule_load_exception(
falco::load_result::load_result::LOAD_ERR_COMPILE_CONDITION,
err,
ctx);
}
// By default rules are enabled/disabled for the default ruleset

View File

@@ -22,7 +22,7 @@ set(
app/actions/helpers_inspector.cpp
app/actions/configure_interesting_sets.cpp
app/actions/create_signal_handlers.cpp
app/actions/daemonize.cpp
app/actions/pidfile.cpp
app/actions/init_falco_engine.cpp
app/actions/init_inspectors.cpp
app/actions/init_clients.cpp
@@ -75,7 +75,6 @@ list(APPEND FALCO_INCLUDE_DIRECTORIES "${FALCO_EXTRA_INCLUDE_DIRS}")
set(
FALCO_DEPENDENCIES
b64
cxxopts
)
@@ -90,7 +89,7 @@ if(USE_BUNDLED_DEPS)
list(APPEND FALCO_DEPENDENCIES yamlcpp)
endif()
if(NOT MINIMAL_BUILD)
if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT MINIMAL_BUILD)
list(
APPEND FALCO_SOURCES
outputs_grpc.cpp
@@ -119,7 +118,7 @@ if(NOT MINIMAL_BUILD)
"${CARES_INCLUDE}"
)
if(USE_BUNDLED_GRPC)
if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND USE_BUNDLED_GRPC)
list(APPEND FALCO_DEPENDENCIES grpc)
list(APPEND FALCO_LIBRARIES "${GRPC_LIBRARIES}")
endif()
@@ -143,6 +142,10 @@ add_library(
${FALCO_SOURCES}
)
if (EMSCRIPTEN)
target_compile_options(falco_application PRIVATE "-sDISABLE_EXCEPTION_CATCHING=0")
endif()
add_dependencies(falco_application ${FALCO_DEPENDENCIES})
target_link_libraries(
@@ -161,7 +164,17 @@ add_dependencies(falco falco_application ${FALCO_DEPENDENCIES})
target_link_libraries(falco falco_application ${FALCO_LIBRARIES})
target_include_directories(falco PUBLIC ${FALCO_INCLUDE_DIRECTORIES})
if(NOT MINIMAL_BUILD)
if (EMSCRIPTEN)
target_compile_options(falco PRIVATE "-sDISABLE_EXCEPTION_CATCHING=0")
target_link_options(falco PRIVATE "-sALLOW_MEMORY_GROWTH=1")
target_link_options(falco PRIVATE "-sDISABLE_EXCEPTION_CATCHING=0")
target_link_options(falco PRIVATE "-sMODULARIZE=1")
target_link_options(falco PRIVATE "-sEXPORT_ES6=1")
target_link_options(falco PRIVATE "-sEXPORTED_RUNTIME_METHODS=['FS', 'callMain']")
target_link_options(falco PRIVATE "-sEXPORTED_FUNCTIONS=['_main','_htons','_ntohs']")
endif()
if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT MINIMAL_BUILD)
add_custom_command(
OUTPUT
${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.cc
@@ -200,4 +213,12 @@ if(MUSL_OPTIMIZED_BUILD AND CMAKE_BUILD_TYPE STREQUAL "release")
)
endif()
install(TARGETS falco RUNTIME DESTINATION ${FALCO_BIN_DIR} COMPONENT "${FALCO_COMPONENT_NAME}")
if (NOT EMSCRIPTEN)
install(TARGETS falco RUNTIME DESTINATION ${FALCO_BIN_DIR} COMPONENT "${FALCO_COMPONENT_NAME}")
else()
install(FILES
"$<TARGET_FILE_DIR:falco>/falco.js"
"$<TARGET_FILE_DIR:falco>/falco.wasm"
DESTINATION ${FALCO_BIN_DIR}
COMPONENT "${FALCO_COMPONENT_NAME}")
endif()

View File

@@ -28,7 +28,7 @@ falco::app::run_result configure_syscall_buffer_size(falco::app::state& s);
falco::app::run_result configure_syscall_buffer_num(falco::app::state& s);
falco::app::run_result create_requested_paths(falco::app::state& s);
falco::app::run_result create_signal_handlers(falco::app::state& s);
falco::app::run_result daemonize(falco::app::state& s);
falco::app::run_result pidfile(falco::app::state& s);
falco::app::run_result init_clients(falco::app::state& s);
falco::app::run_result init_falco_engine(falco::app::state& s);
falco::app::run_result init_inspectors(falco::app::state& s);

View File

@@ -214,6 +214,7 @@ static void select_event_set(falco::app::state& s, const libsinsp::events::set<p
falco::app::run_result falco::app::actions::configure_interesting_sets(falco::app::state& s)
{
#ifdef __linux__
if (s.engine == nullptr || s.config == nullptr)
{
return run_result::fatal("Broken 'configure_interesting_sets' preconditions: engine and config must be non-null");
@@ -232,5 +233,7 @@ falco::app::run_result falco::app::actions::configure_interesting_sets(falco::ap
auto rules_sc_set = s.engine->sc_codes_for_ruleset(falco_common::syscall_source);
select_event_set(s, rules_sc_set);
check_for_rules_unsupported_events(s, rules_sc_set);
#endif
return run_result::ok();
}

View File

@@ -21,6 +21,7 @@ using namespace falco::app::actions;
falco::app::run_result falco::app::actions::configure_syscall_buffer_num(falco::app::state& s)
{
#ifdef __linux__
if(!s.options.modern_bpf)
{
return run_result::ok();
@@ -37,6 +38,6 @@ falco::app::run_result falco::app::actions::configure_syscall_buffer_num(falco::
falco_logger::log(LOG_WARNING, "you required a buffer every '" + std::to_string(s.config->m_cpus_for_each_syscall_buffer) + "' CPUs but there are only '" + std::to_string(online_cpus) + "' online CPUs. Falco changed the config to: one buffer every '" + std::to_string(online_cpus) + "' CPUs\n");
s.config->m_cpus_for_each_syscall_buffer = online_cpus;
}
#endif
return run_result::ok();
}

View File

@@ -26,6 +26,7 @@ using namespace falco::app::actions;
falco::app::run_result falco::app::actions::configure_syscall_buffer_size(falco::app::state& s)
{
#ifdef __linux__
/* We don't need to compute the syscall buffer dimension if we are in capture mode or if the
* the syscall source is not enabled.
*/
@@ -71,5 +72,7 @@ falco::app::run_result falco::app::actions::configure_syscall_buffer_size(falco:
s.syscall_buffer_bytes_size = chosen_size;
falco_logger::log(LOG_INFO, "The chosen syscall buffer dimension is: " + std::to_string(chosen_size) + " bytes (" + std::to_string(chosen_size / (uint64_t)(1024 * 1024)) + " MBs)\n");
#endif // __linux__
return run_result::ok();
}

View File

@@ -20,7 +20,9 @@ limitations under the License.
#include "../app.h"
#include "../signals.h"
#ifdef __linux__
#include <signal.h>
#endif // __linux__
using namespace falco::app;
using namespace falco::app::actions;
@@ -48,6 +50,7 @@ static void restart_signal_handler(int signal)
bool create_handler(int sig, void (*func)(int), run_result &ret)
{
ret = run_result::ok();
#ifdef __linux__
if(signal(sig, func) == SIG_ERR)
{
char errbuf[1024];
@@ -61,12 +64,15 @@ bool create_handler(int sig, void (*func)(int), run_result &ret)
": " +
errbuf);
}
#endif
return ret.success;
}
falco::app::run_result falco::app::actions::create_signal_handlers(falco::app::state& s)
{
auto ret = run_result::ok();
#ifdef __linux__
if (s.options.dry_run)
{
falco_logger::log(LOG_DEBUG, "Skipping signal handlers creation in dry-run\n");
@@ -84,7 +90,6 @@ falco::app::run_result falco::app::actions::create_signal_handlers(falco::app::s
falco_logger::log(LOG_WARNING, "Bundled atomics implementation is not lock-free, signal handlers may be unstable\n");
}
run_result ret;
if(! create_handler(SIGINT, ::terminate_signal_handler, ret) ||
! create_handler(SIGTERM, ::terminate_signal_handler, ret) ||
! create_handler(SIGUSR1, ::reopen_outputs_signal_handler, ret) ||
@@ -146,11 +151,14 @@ falco::app::run_result falco::app::actions::create_signal_handlers(falco::app::s
{
s_restarter = s.restarter;
}
#endif
return ret;
}
falco::app::run_result falco::app::actions::unregister_signal_handlers(falco::app::state& s)
{
#ifdef __linux__
if (s.options.dry_run)
{
falco_logger::log(LOG_DEBUG, "Skipping unregistering signal handlers in dry-run\n");
@@ -171,5 +179,7 @@ falco::app::run_result falco::app::actions::unregister_signal_handlers(falco::ap
{
return ret;
}
#endif // __linux__
return run_result::ok();
}

View File

@@ -1,87 +0,0 @@
/*
Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "actions.h"
using namespace falco::app;
using namespace falco::app::actions;
static bool s_daemonized = false;
falco::app::run_result falco::app::actions::daemonize(falco::app::state& s)
{
if (s.options.dry_run)
{
falco_logger::log(LOG_DEBUG, "Skipping daemonizing in dry-run\n");
return run_result::ok();
}
// If daemonizing, do it here so any init errors will
// be returned in the foreground process.
if (s.options.daemon && !s_daemonized) {
pid_t pid, sid;
pid = fork();
if (pid < 0) {
// error
return run_result::fatal("Could not fork");
} else if (pid > 0) {
// parent. Write child pid to pidfile and exit
std::ofstream pidfile;
pidfile.open(s.options.pidfilename);
if (!pidfile.good())
{
falco_logger::log(LOG_ERR, "Could not write pid to pid file " + s.options.pidfilename + ". Exiting.\n");
exit(-1);
}
pidfile << pid;
pidfile.close();
exit(0);
}
// if here, child.
// Become own process group.
sid = setsid();
if (sid < 0) {
return run_result::fatal("Could not set session id");
}
// Set umask so no files are world anything or group writable.
umask(027);
// Change working directory to '/'
if ((chdir("/")) < 0) {
return run_result::fatal("Could not change working directory to '/'");
}
// Close stdin, stdout, stderr and reopen to /dev/null
close(0);
close(1);
close(2);
open("/dev/null", O_RDONLY);
open("/dev/null", O_RDWR);
open("/dev/null", O_RDWR);
s_daemonized = true;
}
return run_result::ok();
}

View File

@@ -91,7 +91,7 @@ falco::app::run_result falco::app::actions::open_live_inspector(
//
// Falco uses a ptrace(2) based userspace implementation.
// Regardless of the implementation, the underlying method remains the same.
falco_logger::log(LOG_INFO, "Opening '" + source + "' source with udig\n");
falco_logger::log(LOG_WARNING, "The udig engine is deprecated and will be removed in Falco 0.37. Opening '" + source + "' source with udig\n");
inspector->open_udig();
}
else if(s.is_gvisor_enabled()) /* gvisor engine. */

View File

@@ -21,7 +21,7 @@ using namespace falco::app::actions;
falco::app::run_result falco::app::actions::init_clients(falco::app::state& s)
{
#ifndef MINIMAL_BUILD
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
// k8s is useful only if the syscall source is enabled
if (s.is_capture_mode() || !s.is_source_enabled(falco_common::syscall_source))
{

View File

@@ -22,27 +22,32 @@ using namespace falco::app::actions;
void configure_output_format(falco::app::state& s)
{
// See https://falco.org/docs/rules/style-guide/
const std::string container_info = "container_id=%container.id container_image=%container.image.repository container_image_tag=%container.image.tag container_name=%container.name";
const std::string k8s_info = "k8s_ns=%k8s.ns.name k8s_pod_name=%k8s.pod.name";
const std::string gvisor_info = "vpid=%proc.vpid vtid=%thread.vtid";
std::string output_format;
bool replace_container_info = false;
if(s.options.print_additional == "c" || s.options.print_additional == "container")
{
output_format = "container=%container.name (id=%container.id)";
output_format = container_info;
replace_container_info = true;
}
else if(s.options.print_additional == "cg" || s.options.print_additional == "container-gvisor")
{
output_format = "container=%container.name (id=%container.id) vpid=%proc.vpid vtid=%thread.vtid";
output_format = gvisor_info + " " + container_info;
replace_container_info = true;
}
else if(s.options.print_additional == "k" || s.options.print_additional == "kubernetes")
{
output_format = "k8s.ns=%k8s.ns.name k8s.pod=%k8s.pod.name container=%container.id";
output_format = container_info + " " + k8s_info;
replace_container_info = true;
}
else if(s.options.print_additional == "kg" || s.options.print_additional == "kubernetes-gvisor")
{
output_format = "k8s.ns=%k8s.ns.name k8s.pod=%k8s.pod.name container=%container.id vpid=%proc.vpid vtid=%thread.vtid";
output_format = gvisor_info + " " + container_info + " " + k8s_info;
replace_container_info = true;
}
else if(!s.options.print_additional.empty())

View File

@@ -51,7 +51,7 @@ falco::app::run_result falco::app::actions::init_outputs(falco::app::state& s)
if (s.options.dry_run)
{
falco_logger::log(LOG_DEBUG, "Skipping daemonizing in dry-run\n");
falco_logger::log(LOG_DEBUG, "Skipping outputs initialization in dry-run\n");
return run_result::ok();
}
@@ -63,6 +63,8 @@ falco::app::run_result falco::app::actions::init_outputs(falco::app::state& s)
s.config->m_json_include_tags_property,
s.config->m_output_timeout,
s.config->m_buffered_outputs,
s.config->m_outputs_queue_capacity,
s.config->m_outputs_queue_recovery,
s.config->m_time_format_iso_8601,
hostname));

View File

@@ -25,20 +25,7 @@ static void apply_deprecated_options(
const falco::app::options& opts,
const std::shared_ptr<falco_configuration>& cfg)
{
if (!opts.stats_output_file.empty() || !opts.stats_interval.empty())
{
falco_logger::log(LOG_WARNING, "Options '-s' and '--stats-interval' will be deprecated in the future, metrics must be configured through config file");
if (!opts.stats_output_file.empty())
{
cfg->m_metrics_enabled = true;
cfg->m_metrics_output_file = opts.stats_output_file;
if (!opts.stats_interval.empty())
{
cfg->m_metrics_interval_str = opts.stats_interval;
cfg->m_metrics_interval = falco::utils::parse_prometheus_interval(cfg->m_metrics_interval_str);
}
}
}
// Keep for future use cases.
}
falco::app::run_result falco::app::actions::load_config(falco::app::state& s)
@@ -80,13 +67,15 @@ falco::app::run_result falco::app::actions::load_config(falco::app::state& s)
falco::app::run_result falco::app::actions::require_config_file(falco::app::state& s)
{
#ifndef __EMSCRIPTEN__
if (s.options.conf_filename.empty())
{
#ifndef BUILD_TYPE_RELEASE
return run_result::fatal(std::string("You must create a config file at ") + FALCO_SOURCE_CONF_FILE + ", " + FALCO_INSTALL_CONF_FILE + " or by passing -c");
#else
#else // BUILD_TYPE_RELEASE
return run_result::fatal(std::string("You must create a config file at ") + FALCO_INSTALL_CONF_FILE + " or by passing -c");
#endif
#endif // BUILD_TYPE_RELEASE
}
#endif // __EMSCRIPTEN__
return run_result::ok();
}

View File

@@ -22,10 +22,10 @@ using namespace falco::app::actions;
falco::app::run_result falco::app::actions::load_plugins(falco::app::state& s)
{
#ifdef MUSL_OPTIMIZED
#if defined(MUSL_OPTIMIZED) or defined(__EMSCRIPTEN__)
if (!s.config->m_plugins.empty())
{
return run_result::fatal("Can not load/use plugins with musl optimized build");
return run_result::fatal("Loading plugins dynamic libraries is not supported by this Falco build");
}
#endif
// Initialize the set of loaded event sources.

View File

@@ -0,0 +1,52 @@
/*
Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "actions.h"
using namespace falco::app;
using namespace falco::app::actions;
falco::app::run_result falco::app::actions::pidfile(falco::app::state& s)
{
if (s.options.dry_run)
{
falco_logger::log(LOG_DEBUG, "Skipping pidfile creation in dry-run\n");
return run_result::ok();
}
if (!s.options.pidfilename.empty())
{
int64_t self_pid = getpid();
std::ofstream pidfile;
pidfile.open(s.options.pidfilename);
if (!pidfile.good())
{
falco_logger::log(LOG_ERR, "Could not write pid to pidfile " + s.options.pidfilename + ". Exiting.\n");
exit(-1);
}
pidfile << self_pid;
pidfile.close();
}
return run_result::ok();
}

View File

@@ -24,12 +24,6 @@ using namespace falco::app::actions;
falco::app::run_result falco::app::actions::print_plugin_info(falco::app::state& s)
{
#ifdef MUSL_OPTIMIZED
if(!s.options.print_plugin_info.empty())
{
return run_result::fatal("Can not load or use plugins with musl optimized build");
}
#else // MUSL_OPTIMIZED
if(!s.options.print_plugin_info.empty())
{
std::unique_ptr<sinsp> inspector(new sinsp());
@@ -110,7 +104,6 @@ falco::app::run_result falco::app::actions::print_plugin_info(falco::app::state&
}
return run_result::fatal("can't find plugin and print its info: " + s.options.print_plugin_info);
}
#endif // MUSL_OPTIMIZED
return run_result::ok();
}

View File

@@ -16,6 +16,8 @@ limitations under the License.
#include "actions.h"
#include "helpers.h"
#include "../app.h"
#include "../../versions_info.h"
using namespace falco::app;
using namespace falco::app::actions;
@@ -28,10 +30,56 @@ struct event_entry
const ppm_event_info* info;
};
static std::vector<event_entry> get_event_entries(bool include_generics, const libsinsp::events::set<ppm_event_code>& available)
struct events_by_category
{
event_entry entry;
std::vector<event_entry> events;
std::vector<event_entry> syscalls;
std::vector<event_entry> tracepoints;
std::vector<event_entry> pluginevents;
std::vector<event_entry> metaevents;
void add_event(ppm_event_code e, bool available, std::string name = "") {
event_entry entry;
entry.is_enter = PPME_IS_ENTER(e);
entry.info = libsinsp::events::info(e);
entry.available = available;
if (name == "")
{
entry.name = entry.info->name;
} else {
entry.name = name;
}
if (libsinsp::events::is_syscall_event(e))
{
syscalls.push_back(entry);
return;
}
if (libsinsp::events::is_tracepoint_event(e))
{
tracepoints.push_back(entry);
return;
}
if (libsinsp::events::is_plugin_event(e))
{
pluginevents.push_back(entry);
return;
}
if (libsinsp::events::is_metaevent(e))
{
metaevents.push_back(entry);
return;
}
}
};
static struct events_by_category get_event_entries_by_category(bool include_generics, const libsinsp::events::set<ppm_event_code>& available)
{
events_by_category result;
// skip generic events
for (const auto& e: libsinsp::events::all_event_set())
@@ -41,11 +89,7 @@ static std::vector<event_entry> get_event_entries(bool include_generics, const l
&& !libsinsp::events::is_unused_event(e)
&& !libsinsp::events::is_unknown_event(e))
{
entry.is_enter = PPME_IS_ENTER(e);
entry.available = available.contains(e);
entry.info = libsinsp::events::info(e);
entry.name = entry.info->name;
events.push_back(entry);
result.add_event(e, available.contains(e));
}
}
@@ -55,60 +99,104 @@ static std::vector<event_entry> get_event_entries(bool include_generics, const l
const auto names = libsinsp::events::event_set_to_names({ppm_event_code::PPME_GENERIC_E});
for (const auto& name : names)
{
entry.is_enter = PPME_IS_ENTER(ppm_event_code::PPME_GENERIC_E);
entry.available = available.contains(ppm_event_code::PPME_GENERIC_E);
entry.info = libsinsp::events::info(ppm_event_code::PPME_GENERIC_E);
entry.name = name;
events.push_back(entry);
entry.is_enter = PPME_IS_ENTER(ppm_event_code::PPME_GENERIC_X);
entry.available = available.contains(ppm_event_code::PPME_GENERIC_X);
entry.info = libsinsp::events::info(ppm_event_code::PPME_GENERIC_X);
entry.name = name;
events.push_back(entry);
result.add_event(ppm_event_code::PPME_GENERIC_E, available.contains(ppm_event_code::PPME_GENERIC_E), name);
result.add_event(ppm_event_code::PPME_GENERIC_X, available.contains(ppm_event_code::PPME_GENERIC_X), name);
}
}
return events;
return result;
}
static bool is_flag_type(ppm_param_type type)
{
return (type == PT_FLAGS8 || type == PT_FLAGS16 || type == PT_FLAGS32 ||
type == PT_ENUMFLAGS8 || type == PT_ENUMFLAGS16 || type == PT_ENUMFLAGS32);
}
static void print_param(const struct ppm_param_info *param, bool markdown) {
printf("%s **%s**", param_type_to_string(param->type), param->name);
if (is_flag_type(param->type) && param->info) {
auto flag_info = static_cast<const ppm_name_value*>(param->info);
printf(": ");
for (size_t i = 0; flag_info[i].name != NULL; i++) {
if (i != 0)
{
printf(", ");
}
if (markdown) {
printf("*%s*", flag_info[i].name);
} else {
printf("%s", flag_info[i].name);
}
}
}
}
static void print_events(const std::vector<event_entry> &events, bool markdown)
{
if(markdown)
{
printf("Default | Dir | Name | Params \n");
printf(":-------|:----|:-----|:-----\n");
}
for (const auto& e : events)
{
char dir = e.is_enter ? '>' : '<';
if (markdown)
{
printf(e.available ? "Yes" : "No");
printf(" | `%c` | `%s` | ", dir, e.name.c_str());
}
else
{
printf("%c %s(", dir, e.name.c_str());
}
for(uint32_t k = 0; k < e.info->nparams; k++)
{
if(k != 0)
{
printf(", ");
}
print_param(&e.info->params[k], markdown);
}
if (markdown)
{
printf("\n");
}
else
{
printf(")\n");
}
}
}
falco::app::run_result falco::app::actions::print_syscall_events(falco::app::state& s)
{
if(s.options.list_syscall_events)
{
const auto events = get_event_entries(true, libsinsp::events::all_event_set());
const falco::versions_info info(s.offline_inspector);
printf("The events below are valid for Falco *Schema Version*: %s\n", info.driver_schema_version.c_str());
if(s.options.markdown)
{
printf("Falco | Dir | Event\n");
printf(":-----|:----|:-----\n");
}
const libsinsp::events::set<ppm_event_code> available = libsinsp::events::all_event_set().diff(sc_set_to_event_set(falco::app::ignored_sc_set()));
const struct events_by_category events_bc = get_event_entries_by_category(true, available);
for (const auto& e : events)
{
char dir = e.is_enter ? '>' : '<';
if (s.options.markdown)
{
printf(e.available ? "Yes" : "No");
printf(" | %c | **%s**(", dir, e.name.c_str());
}
else
{
printf("%c %s(", dir, e.name.c_str());
}
printf("## Syscall events\n\n");
print_events(events_bc.syscalls, s.options.markdown);
for(uint32_t k = 0; k < e.info->nparams; k++)
{
if(k != 0)
{
printf(", ");
}
printf("\n\n## Tracepoint events\n\n");
print_events(events_bc.tracepoints, s.options.markdown);
printf("%s %s", param_type_to_string(e.info->params[k].type),
e.info->params[k].name);
}
printf(")\n");
}
printf("\n\n## Plugin events\n\n");
print_events(events_bc.pluginevents, s.options.markdown);
printf("\n\n## Metaevents\n\n");
print_events(events_bc.metaevents, s.options.markdown);
return run_result::exit();
}

View File

@@ -30,13 +30,10 @@ limitations under the License.
#include "helpers.h"
#include "../options.h"
#include "../signals.h"
#include "../../semaphore.h"
#include "../../falco_semaphore.h"
#include "../../stats_writer.h"
#include "../../falco_outputs.h"
#include "../../event_drops.h"
#ifndef MINIMAL_BUILD
#include "../../webserver.h"
#endif
#include <plugin_manager.h>
@@ -430,15 +427,14 @@ static falco::app::run_result init_stats_writer(
if(std::all_of(config->m_metrics_interval_str.begin(), config->m_metrics_interval_str.end(), ::isdigit))
{
falco_logger::log(LOG_WARNING, "Metrics interval was passed as numeric value without Prometheus time unit, this option will be deprecated in the future");
return falco::app::run_result::fatal("Metrics interval was passed as numeric value without Prometheus time unit. Please specify a time unit");
}
if (config->m_metrics_enabled && !sw->has_output())
{
falco_logger::log(LOG_WARNING, "Metrics are enabled with no output configured, no snapshot will be collected");
return falco::app::run_result::fatal("Metrics are enabled with no output configured. Please enable at least one output channel");
}
falco_logger::log(LOG_INFO, "Setting metrics interval to " + config->m_metrics_interval_str + ", equivalent to " + std::to_string(config->m_metrics_interval) + " (ms)\n");
auto res = falco::app::run_result::ok();
@@ -496,6 +492,13 @@ falco::app::run_result falco::app::actions::process_events(falco::app::state& s)
{
print_enabled_event_sources(s);
#ifdef __EMSCRIPTEN__
if(s.enabled_sources.size() > 1)
{
return run_result::fatal("enabling multiple event sources is not supported by this Falco build");
}
#endif
// start event processing for all enabled sources
falco::semaphore termination_sem(s.enabled_sources.size());
std::vector<live_context> ctxs;

View File

@@ -16,7 +16,7 @@ limitations under the License.
#include "actions.h"
#ifndef MINIMAL_BUILD
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
#include "grpc_server.h"
#endif
@@ -25,7 +25,7 @@ using namespace falco::app::actions;
falco::app::run_result falco::app::actions::start_grpc_server(falco::app::state& s)
{
#ifndef MINIMAL_BUILD
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
// gRPC server
if(s.config->m_grpc_enabled)
{
@@ -56,7 +56,7 @@ falco::app::run_result falco::app::actions::start_grpc_server(falco::app::state&
falco::app::run_result falco::app::actions::stop_grpc_server(falco::app::state& s)
{
#ifndef MINIMAL_BUILD
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
if(s.config->m_grpc_enabled)
{
if (s.options.dry_run)

View File

@@ -16,7 +16,7 @@ limitations under the License.
#include "actions.h"
#ifndef MINIMAL_BUILD
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
#include "webserver.h"
#endif
@@ -25,7 +25,7 @@ using namespace falco::app::actions;
falco::app::run_result falco::app::actions::start_webserver(falco::app::state& s)
{
#ifndef MINIMAL_BUILD
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
if(!s.is_capture_mode() && s.config->m_webserver_enabled)
{
if (s.options.dry_run)
@@ -55,7 +55,7 @@ falco::app::run_result falco::app::actions::start_webserver(falco::app::state& s
falco::app::run_result falco::app::actions::stop_webserver(falco::app::state& s)
{
#ifndef MINIMAL_BUILD
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
if(!s.is_capture_mode() && s.config->m_webserver_enabled)
{
if (s.options.dry_run)

View File

@@ -80,7 +80,7 @@ bool falco::app::run(falco::app::state& s, bool& restart, std::string& errstr)
falco::app::actions::init_outputs,
falco::app::actions::create_signal_handlers,
falco::app::actions::create_requested_paths,
falco::app::actions::daemonize,
falco::app::actions::pidfile,
falco::app::actions::init_clients,
falco::app::actions::configure_interesting_sets,
falco::app::actions::configure_syscall_buffer_size,

View File

@@ -36,6 +36,7 @@ options::options()
list_plugins(false),
list_syscall_events(false),
markdown(false),
userspace(false),
modern_bpf(false),
dry_run(false),
nodriver(false)
@@ -142,11 +143,6 @@ bool options::parse(int argc, char **argv, std::string &errstr)
return false;
}
if (daemon && pidfilename == "") {
errstr = std::string("If -d is provided, a pid file must also be provided");
return false;
}
list_fields = m_cmdline_parsed.count("list") > 0 ? true : false;
int open_modes = 0;
@@ -173,64 +169,63 @@ const std::string& options::usage()
void options::define(cxxopts::Options& opts)
{
opts.add_options()
("h,help", "Print this page", cxxopts::value(help)->default_value("false"))
("h,help", "Print this help list and exit.", cxxopts::value(help)->default_value("false"))
#ifdef BUILD_TYPE_RELEASE
("c", "Configuration file. If not specified uses " FALCO_INSTALL_CONF_FILE ".", cxxopts::value(conf_filename), "<path>")
#else
("c", "Configuration file. If not specified tries " FALCO_SOURCE_CONF_FILE ", " FALCO_INSTALL_CONF_FILE ".", cxxopts::value(conf_filename), "<path>")
#endif
("A", "Monitor all events supported by Falco defined in rules and configs. Please use the -i option to list the events ignored by default without -A. This option affects live captures only. Setting -A can impact performance.", cxxopts::value(all_events)->default_value("false"))
("A", "Monitor all events supported by Falco and defined in rules and configs. Some events are ignored by default when -A is not specified (the -i option lists these events ignored). Using -A can impact performance. This option has no effect when reproducing events from a capture file.", cxxopts::value(all_events)->default_value("false"))
("b,print-base64", "Print data buffers in base64. This is useful for encoding binary data that needs to be used over media designed to consume this format.")
("cri", "Path to CRI socket for container metadata. Use the specified socket to fetch data from a CRI-compatible runtime. If not specified, uses the libs default. This option can be passed multiple times to specify socket to be tried until a successful one is found.", cxxopts::value(cri_socket_paths), "<path>")
("d,daemon", "Run as a daemon.", cxxopts::value(daemon)->default_value("false"))
("disable-cri-async", "Disable asynchronous CRI metadata fetching. This is useful to let the input event wait for the container metadata fetch to finish before moving forward. Async fetching, in some environments leads to empty fields for container metadata when the fetch is not fast enough to be completed asynchronously. This can have a performance penalty on your environment depending on the number of containers and the frequency at which they are created/started/stopped.", cxxopts::value(disable_cri_async)->default_value("false"))
("disable-source", "Disable a specific event source. By default, all loaded sources get enabled. Available sources are 'syscall' and all sources defined by loaded plugins supporting the event sourcing capability. This option can be passed multiple times. This has no offect when reading events from a trace file. Can not disable all event sources. Can not be mixed with --enable-source.", cxxopts::value(disable_sources), "<event_source>")
("dry-run", "Run Falco without proceesing events. Can be useful for checking that the configuration and rules do not have any errors.", cxxopts::value(dry_run)->default_value("false"))
("D", "Disable any rules with names having the substring <substring>. This option can be passed multiple times. Can not be mixed with -t.", cxxopts::value(disabled_rule_substrings), "<substring>")
("e", "Read the events from a trace file <events_file> in .scap format instead of tapping into live.", cxxopts::value(trace_filename), "<events_file>")
("enable-source", "Enable a specific event source. If used, all loaded sources get disabled by default and only the ones passed with this option get enabled. Available sources are 'syscall' and all sources defined by loaded plugins supporting the event sourcing capability. This option can be passed multiple times. This has no offect when reading events from a trace file. Can not be mixed with --disable-source.", cxxopts::value(enable_sources), "<event_source>")
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
("cri", "Path to CRI socket for container metadata. Use the specified <path> to fetch data from a CRI-compatible runtime. If not specified, built-in defaults for commonly known paths are used. This option can be passed multiple times to specify a list of sockets to be tried until a successful one is found.", cxxopts::value(cri_socket_paths), "<path>")
("disable-cri-async", "Turn off asynchronous CRI metadata fetching. This is useful to let the input event wait for the container metadata fetch to finish before moving forward. Async fetching, in some environments leads to empty fields for container metadata when the fetch is not fast enough to be completed asynchronously. This can have a performance penalty on your environment depending on the number of containers and the frequency at which they are created/started/stopped.", cxxopts::value(disable_cri_async)->default_value("false"))
#endif
("disable-source", "Turn off a specific <event_source>. By default, all loaded sources get enabled. Available sources are 'syscall' plus all sources defined by loaded plugins supporting the event sourcing capability. This option can be passed multiple times, but turning off all event sources simultaneously is not permitted. This option can not be mixed with --enable-source. This option has no effect when reproducing events from a capture file.", cxxopts::value(disable_sources), "<event_source>")
("dry-run", "Run Falco without processing events. It can help check that the configuration and rules do not have any errors.", cxxopts::value(dry_run)->default_value("false"))
("D", "Turn off any rules with names having the substring <substring>. This option can be passed multiple times. It cannot be mixed with -t.", cxxopts::value(disabled_rule_substrings), "<substring>")
("e", "Reproduce the events by reading from the given <capture_file> instead of opening a live session. Only capture files in .scap format are supported.", cxxopts::value(trace_filename), "<events_file>")
("enable-source", "Enable a specific <event_source>. By default, all loaded sources get enabled. Available sources are 'syscall' plus all sources defined by loaded plugins supporting the event sourcing capability. This option can be passed multiple times. When using this option, only the event sources specified by it will be enabled. This option can not be mixed with --disable-source. This option has no effect when reproducing events from a capture file.", cxxopts::value(enable_sources), "<event_source>")
#ifdef HAS_GVISOR
("g,gvisor-config", "Parse events from gVisor using the specified configuration file. A falco-compatible configuration file can be generated with --gvisor-generate-config and can be used for both runsc and Falco.", cxxopts::value(gvisor_config), "<gvisor_config>")
("gvisor-generate-config", "Generate a configuration file that can be used for gVisor.", cxxopts::value<std::string>(gvisor_generate_config_with_socket)->implicit_value("/run/falco/gvisor.sock"), "<socket_path>")
("gvisor-root", "gVisor root directory for storage of container state. Equivalent to runsc --root flag.", cxxopts::value(gvisor_root), "<gvisor_root>")
("g,gvisor-config", "Collect 'syscall' events from gVisor using the specified <gvisor_config> file. A Falco-compatible configuration file can be generated with --gvisor-generate-config and utilized for both runsc and Falco.", cxxopts::value(gvisor_config), "<gvisor_config>")
("gvisor-generate-config", "Generate a configuration file that can be used for gVisor and exit. See --gvisor-config for more details.", cxxopts::value<std::string>(gvisor_generate_config_with_socket)->implicit_value("/run/falco/gvisor.sock"), "<socket_path>")
("gvisor-root", "Set gVisor root directory for storage of container state when used in conjunction with --gvisor-config. The <gvisor_root> to be passed is the one usually passed to runsc --root flag.", cxxopts::value(gvisor_root), "<gvisor_root>")
#endif
#ifdef HAS_MODERN_BPF
("modern-bpf", "Use BPF modern probe driver to instrument the kernel.", cxxopts::value(modern_bpf)->default_value("false"))
("modern-bpf", "Use the BPF modern probe driver to instrument the kernel and observe 'syscall' events.", cxxopts::value(modern_bpf)->default_value("false"))
#endif
("i", "Print all high volume syscalls that are ignored by default for performance reasons (i.e. without the -A flag) and exit.", cxxopts::value(print_ignored_events)->default_value("false"))
#ifndef MINIMAL_BUILD
("k,k8s-api", "Enable Kubernetes support by connecting to the API server specified as argument. E.g. \"http://admin:password@127.0.0.1:8080\". The API server can also be specified via the environment variable FALCO_K8S_API.", cxxopts::value(k8s_api), "<url>")
("K,k8s-api-cert", "Use the provided files names to authenticate user and (optionally) verify the K8S API server identity. Each entry must specify full (absolute, or relative to the current directory) path to the respective file. Private key password is optional (needed only if key is password protected). CA certificate is optional. For all files, only PEM file format is supported. Specifying CA certificate only is obsoleted - when single entry is provided for this option, it will be interpreted as the name of a file containing bearer token. Note that the format of this command-line option prohibits use of files whose names contain ':' or '#' characters in the file name.", cxxopts::value(k8s_api_cert), "(<bt_file> | <cert_file>:<key_file[#password]>[:<ca_cert_file>])")
("k8s-node", "The node name will be used as a filter when requesting metadata of pods to the API server. Usually, this should be set to the current node on which Falco is running. If empty, no filter is set, which may have a performance penalty on large clusters.", cxxopts::value(k8s_node_name), "<node_name>")
("i", "Print those events that are ignored by default for performance reasons and exit. See -A for more details.", cxxopts::value(print_ignored_events)->default_value("false"))
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
("k,k8s-api", "Enable Kubernetes metadata support by connecting to the given API server <URL>\n(e.g. \"http://admin:password@127.0.0.1:8080\". The API server can also be specified via the environment variable FALCO_K8S_API.", cxxopts::value(k8s_api), "<URL>")
("K,k8s-api-cert", "Use the provided file names to authenticate the user and (optionally) verify the K8S API server identity. Each entry must specify the full (absolute or relative to the current directory) path to the respective file. Passing a private key password is optional (unless the key is password-protected). CA certificate is optional. For all files, only the PEM file format is supported. Specifying the CA certificate only is obsoleted - when a single entry is provided for this option, it will be interpreted as the name of a file containing the bearer token. Note that the format of this command-line option prohibits the use of files whose names contain ':' or '#' characters in the file name. This option has effect only when used in conjunction with -k.", cxxopts::value(k8s_api_cert), "(<bt_file> | <cert_file>:<key_file[#password]>[:<ca_cert_file>])")
("k8s-node", "Filter Kubernetes metadata for a specified <node_name>. The node name will be used as a filter when requesting metadata of pods to the API server. Usually, this should be set to the current node on which Falco is running. No filter is set if empty, which may have a performance penalty on large clusters. This option has effect only when used in conjunction with -k.", cxxopts::value(k8s_node_name), "<node_name>")
#endif
("L", "Show the name and description of all rules and exit. If json_output is set to true, it prints details about all rules, macros and lists in JSON format", cxxopts::value(describe_all_rules)->default_value("false"))
("l", "Show the name and description of the rule with name <rule> and exit. If json_output is set to true, it prints details about the rule in JSON format", cxxopts::value(describe_rule), "<rule>")
("list", "List all defined fields. If <source> is provided, only list those fields for the source <source>. Current values for <source> are \"syscall\" or any source from a configured plugin with event sourcing capability.", cxxopts::value(list_source_fields)->implicit_value(""), "<source>")
("list-syscall-events", "List all defined system call events.", cxxopts::value<bool>(list_syscall_events))
#ifndef MUSL_OPTIMIZED
("L", "Show the name and description of all rules and exit. If json_output is set to true, it prints details about all rules, macros, and lists in JSON format.", cxxopts::value(describe_all_rules)->default_value("false"))
("l", "Show the name and description of the rule specified <rule> and exit. If json_output is set to true, it prints details about the rule in JSON format.", cxxopts::value(describe_rule), "<rule>")
("list", "List all defined fields and exit. If <source> is provided, only list those fields for the source <source>. Current values for <source> are \"syscall\" or any source from a configured plugin with event sourcing capability.", cxxopts::value(list_source_fields)->implicit_value(""), "<source>")
("list-events", "List all defined syscall events, metaevents, tracepoint events and exit.", cxxopts::value<bool>(list_syscall_events))
("list-plugins", "Print info on all loaded plugins and exit.", cxxopts::value(list_plugins)->default_value("false"))
("M", "Stop Falco execution after <num_seconds> are passed.", cxxopts::value(duration_to_tot)->default_value("0"), "<num_seconds>")
("markdown", "Print output in Markdown format when used in conjunction with --list or --list-events options. It has no effect when used with other options.", cxxopts::value<bool>(markdown))
("N", "Only print field names when used in conjunction with the --list option. It has no effect when used with other options.", cxxopts::value(names_only)->default_value("false"))
("nodriver", "Do not use a driver to instrument the kernel. If a loaded plugin has event-sourcing capability and can produce system events, it will be used for event collection. Otherwise, no event will be collected.", cxxopts::value(nodriver)->default_value("false"))
("o,option", "Set the value of option <opt> to <val>. Overrides values in the configuration file. <opt> can be identified using its location in the configuration file using dot notation. Elements of list entries can be accessed via square brackets [].\n E.g. base.id = val\n base.subvalue.subvalue2 = val\n base.list[1]=val", cxxopts::value(cmdline_config_options), "<opt>=<val>")
("plugin-info", "Print info for the plugin specified by <plugin_name> and exit.\nThis includes all descriptive information like name and author, along with the\nschema format for the init configuration and a list of suggested open parameters.\n<plugin_name> can be the plugin's name or its configured 'library_path'.", cxxopts::value(print_plugin_info), "<plugin_name>")
("p,print", "Print (or replace) additional information in the rule's output.\nUse -pc or -pcontainer to append container details.\nUse -pk or -pkubernetes to add both container and Kubernetes details.\nIf using gVisor, choose -pcg or -pkg variants (or -pcontainer-gvisor and -pkubernetes-gvisor, respectively).\nIf a rule's output contains %container.info, it will be replaced with the corresponding details. Otherwise, these details will be directly appended to the rule's output.\nAlternatively, use -p <output_format> for a custom format. In this case, the given <output_format> will be appended to the rule's output without any replacement.", cxxopts::value(print_additional), "<output_format>")
("P,pidfile", "Write PID to specified <pid_file> path. By default, no PID file is created.", cxxopts::value(pidfilename)->default_value(""), "<pid_file>")
("r", "Rules file or directory to be loaded. This option can be passed multiple times. Falco defaults to the values in the configuration file when this option is not specified.", cxxopts::value<std::vector<std::string>>(), "<rules_file>")
("S,snaplen", "Collect only the first <len> bytes of each I/O buffer for 'syscall' events. By default, the first 80 bytes are collected by the driver and sent to the user space for processing. Use this option with caution since it can have a strong performance impact.", cxxopts::value(snaplen)->default_value("0"), "<len>")
("support", "Print support information, including version, rules files used, loaded configuration, etc., and exit. The output is in JSON format.", cxxopts::value(print_support)->default_value("false"))
("T", "Turn off any rules with a tag=<tag>. This option can be passed multiple times. This option can not be mixed with -t.", cxxopts::value<std::vector<std::string>>(), "<tag>")
("t", "Only enable those rules with a tag=<tag>. This option can be passed multiple times. This option can not be mixed with -T/-D.", cxxopts::value<std::vector<std::string>>(), "<tag>")
("U,unbuffered", "Turn off output buffering for configured outputs. This causes every single line emitted by Falco to be flushed, which generates higher CPU usage but is useful when piping those outputs into another process or a script.", cxxopts::value(unbuffered_outputs)->default_value("false"))
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
("u,userspace", "[DEPRECATED: this option will be removed in Falco 0.37] Use a userspace driver to collect 'syscall' events. To be used in conjunction with the ptrace(2) based driver (pdig).", cxxopts::value(userspace)->default_value("false"))
#endif
("M", "Stop collecting after <num_seconds> reached.", cxxopts::value(duration_to_tot)->default_value("0"), "<num_seconds>")
("markdown", "When used with --list/--list-syscall-events, print the content in Markdown format", cxxopts::value<bool>(markdown))
("N", "When used with --list, only print field names.", cxxopts::value(names_only)->default_value("false"))
("nodriver", "Do not use a driver to instrument the kernel. If a loaded plugin has event sourcing capability and can produce system events, it will be used to for event collection.", cxxopts::value(nodriver)->default_value("false"))
("o,option", "Set the value of option <opt> to <val>. Overrides values in configuration file. <opt> can be identified using its location in configuration file using dot notation. Elements which are entries of lists can be accessed via square brackets [].\n E.g. base.id = val\n base.subvalue.subvalue2 = val\n base.list[1]=val", cxxopts::value(cmdline_config_options), "<opt>=<val>")
("plugin-info", "Print info for a single plugin and exit.\nThis includes all descriptivo info like name and author, along with the\nschema format for the init configuration and a list of suggested open parameters.\n<plugin_name> can be the name of the plugin or its configured library_path.", cxxopts::value(print_plugin_info), "<plugin_name>")
("p,print", "Add additional information to each falco notification's output.\nWith -pc or -pcontainer will use a container-friendly format.\nWith -pk or -pkubernetes will use a kubernetes-friendly format.\nAdditionally, specifying -pc/-pk will change the interpretation of %container.info in rule output fields.", cxxopts::value(print_additional), "<output_format>")
("P,pidfile", "When run as a daemon, write pid to specified file", cxxopts::value(pidfilename)->default_value("/var/run/falco.pid"), "<pid_file>")
("r", "Rules file/directory (defaults to value set in configuration file, or /etc/falco_rules.yaml). This option can be passed multiple times to read from multiple files/directories.", cxxopts::value<std::vector<std::string>>(), "<rules_file>")
("s", "If specified, append statistics related to Falco's reading/processing of events to this file (only useful in live mode).", cxxopts::value(stats_output_file), "<stats_file>")
("stats-interval", "When using -s <stats_file>, write statistics every <msec> ms. This uses signals, and has a minimum threshold of 100 ms. Defaults to 5000 (5 seconds).", cxxopts::value(stats_interval), "<msec>")
("S,snaplen", "Capture the first <len> bytes of each I/O buffer. By default, the first 80 bytes are captured. Use this option with caution, it can have a strong performance impact.", cxxopts::value(snaplen)->default_value("0"), "<len>")
("support", "Print support information including version, rules files used, etc. and exit.", cxxopts::value(print_support)->default_value("false"))
("T", "Disable any rules with a tag=<tag>. This option can be passed multiple times. Can not be mized with -t", cxxopts::value<std::vector<std::string>>(), "<tag>")
("t", "Only run those rules with a tag=<tag>. This option can be passed multiple times. Can not be mixed with -T/-D.", cxxopts::value<std::vector<std::string>>(), "<tag>")
("U,unbuffered", "Turn off output buffering to configured outputs. This causes every single line emitted by falco to be flushed which generates higher CPU usage but is useful when piping those outputs into another process or into a script.", cxxopts::value(unbuffered_outputs)->default_value("false"))
("u,userspace", "Parse events from userspace. To be used in conjunction with the ptrace(2) based driver (pdig)", cxxopts::value(userspace)->default_value("false"))
("V,validate", "Read the contents of the specified rules(s) file and exit. This option can be passed multiple times to validate multiple files.", cxxopts::value(validate_rules_filenames), "<rules_file>")
("v", "Verbose output.", cxxopts::value(verbose)->default_value("false"))
("version", "Print version number.", cxxopts::value(print_version_info)->default_value("false"))
("page-size", "Print the system page size (may help you to choose the right syscall ring-buffer size).", cxxopts::value(print_page_size)->default_value("false"));
("V,validate", "Read the contents of the specified <rules_file> file(s), validate the loaded rules, and exit. This option can be passed multiple times to validate multiple files.", cxxopts::value(validate_rules_filenames), "<rules_file>")
("v", "Enable verbose output.", cxxopts::value(verbose)->default_value("false"))
("version", "Print version information and exit.", cxxopts::value(print_version_info)->default_value("false"))
("page-size", "Print the system page size and exit. This utility may help choose the right syscall ring buffer size.", cxxopts::value(print_page_size)->default_value("false"));
opts.set_width(140);

View File

@@ -42,7 +42,6 @@ public:
bool all_events;
sinsp_evt::param_fmt event_buffer_format;
std::vector<std::string> cri_socket_paths;
bool daemon;
bool disable_cri_async;
std::vector<std::string> disable_sources;
std::vector<std::string> disabled_rule_substrings;
@@ -70,8 +69,6 @@ public:
std::string pidfilename;
// Rules list as passed by the user, via cmdline option '-r'
std::list<std::string> rules_filenames;
std::string stats_output_file;
std::string stats_interval;
uint64_t snaplen;
bool print_support;
std::set<std::string> disabled_rule_tags;

View File

@@ -31,8 +31,9 @@ limitations under the License.
falco::app::restart_handler::~restart_handler()
{
close(m_inotify_fd);
stop();
close(m_inotify_fd);
m_inotify_fd = -1;
}
void falco::app::restart_handler::trigger()
@@ -42,6 +43,7 @@ void falco::app::restart_handler::trigger()
bool falco::app::restart_handler::start(std::string& err)
{
#ifdef __linux__
m_inotify_fd = inotify_init();
if (m_inotify_fd < 0)
{
@@ -73,16 +75,19 @@ bool falco::app::restart_handler::start(std::string& err)
// launch the watcher thread
m_watcher = std::thread(&falco::app::restart_handler::watcher_loop, this);
#endif
return true;
}
void falco::app::restart_handler::stop()
{
#ifdef __linux__
m_stop.store(true, std::memory_order_release);
if (m_watcher.joinable())
{
m_watcher.join();
}
#endif
}
void falco::app::restart_handler::watcher_loop() noexcept

View File

@@ -22,7 +22,7 @@ limitations under the License.
#include "restart_handler.h"
#include "../configuration.h"
#include "../stats_writer.h"
#ifndef MINIMAL_BUILD
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
#include "../grpc_server.h"
#include "../webserver.h"
#endif
@@ -137,7 +137,7 @@ struct state
// Helper responsible for watching of handling hot application restarts
std::shared_ptr<restart_handler> restarter;
#ifndef MINIMAL_BUILD
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
falco::grpc::server grpc_server;
std::thread grpc_server_thread;

View File

@@ -37,9 +37,11 @@ falco_configuration::falco_configuration():
m_json_include_tags_property(true),
m_notifications_rate(0),
m_notifications_max_burst(1000),
m_watch_config_files(true),
m_rule_matching(falco_common::rule_matching::FIRST),
m_watch_config_files(true),
m_buffered_outputs(false),
m_outputs_queue_capacity(DEFAULT_OUTPUTS_QUEUE_CAPACITY_UNBOUNDED_MAX_LONG_VALUE),
m_outputs_queue_recovery(falco_common::RECOVERY_EXIT),
m_time_format_iso_8601(false),
m_output_timeout(2000),
m_grpc_enabled(false),
@@ -194,6 +196,10 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h
bool insecure;
insecure = config.get_scalar<bool>("http_output.insecure", false);
http_output.options["insecure"] = insecure? std::string("true") : std::string("false");
bool echo;
echo = config.get_scalar<bool>("http_output.echo", false);
http_output.options["echo"] = echo? std::string("true") : std::string("false");
std::string ca_cert;
ca_cert = config.get_scalar<std::string>("http_output.ca_cert", "");
@@ -207,6 +213,18 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h
ca_path = config.get_scalar<std::string>("http_output.ca_path", "/etc/ssl/certs");
http_output.options["ca_path"] = ca_path;
bool mtls;
mtls = config.get_scalar<bool>("http_output.mtls", false);
http_output.options["mtls"] = mtls? std::string("true") : std::string("false");
std::string client_cert;
client_cert = config.get_scalar<std::string>("http_output.client_cert", "/etc/ssl/certs/client.crt");
http_output.options["client_cert"] = client_cert;
std::string client_key;
client_key = config.get_scalar<std::string>("http_output.client_key", "/etc/ssl/certs/client.key");
http_output.options["client_key"] = client_key;
m_outputs.push_back(http_output);
}
@@ -240,9 +258,16 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h
config.get_scalar<std::string>("libs_logger.severity", "debug"),
"[libs]: ");
falco_logger::log_stderr = config.get_scalar<bool>("log_stderr", false);
falco_logger::log_syslog = config.get_scalar<bool>("log_syslog", true);
m_output_timeout = config.get_scalar<uint32_t>("output_timeout", 2000);
m_notifications_rate = config.get_scalar<uint32_t>("outputs.rate", 0);
if(m_notifications_rate != 0)
{
falco_logger::log(LOG_WARNING, "'output.rate' config is deprecated and it will be removed in Falco 0.37\n");
}
m_notifications_max_burst = config.get_scalar<uint32_t>("outputs.max_burst", 1000);
std::string rule_matching = config.get_scalar<std::string>("rule_matching", "first");
@@ -258,10 +283,19 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h
}
m_buffered_outputs = config.get_scalar<bool>("buffered_outputs", false);
m_time_format_iso_8601 = config.get_scalar<bool>("time_format_iso_8601", false);
m_outputs_queue_capacity = config.get_scalar<size_t>("outputs_queue.capacity", DEFAULT_OUTPUTS_QUEUE_CAPACITY_UNBOUNDED_MAX_LONG_VALUE);
// We use 0 in falco.yaml to indicate an unbounded queue; equivalent to the largest long value
if (m_outputs_queue_capacity == 0)
{
m_outputs_queue_capacity = DEFAULT_OUTPUTS_QUEUE_CAPACITY_UNBOUNDED_MAX_LONG_VALUE;
}
std::string recovery = config.get_scalar<std::string>("outputs_queue.recovery", "exit");
if (!falco_common::parse_queue_recovery(recovery, m_outputs_queue_recovery))
{
throw std::logic_error("Unknown recovery \"" + recovery + "\"--must be one of exit, continue, empty");
}
falco_logger::log_stderr = config.get_scalar<bool>("log_stderr", false);
falco_logger::log_syslog = config.get_scalar<bool>("log_syslog", true);
m_time_format_iso_8601 = config.get_scalar<bool>("time_format_iso_8601", false);
m_webserver_enabled = config.get_scalar<bool>("webserver.enabled", false);
m_webserver_threadiness = config.get_scalar<uint32_t>("webserver.threadiness", 0);

View File

@@ -72,6 +72,8 @@ public:
bool m_watch_config_files;
bool m_buffered_outputs;
size_t m_outputs_queue_capacity;
falco_common::outputs_queue_recovery_type m_outputs_queue_recovery;
bool m_time_format_iso_8601;
uint32_t m_output_timeout;

View File

@@ -86,6 +86,8 @@ bool syscall_evt_drop_mgr::process_event(std::shared_ptr<sinsp> inspector, sinsp
delta.n_drops_buffer_dir_file_exit = stats.n_drops_buffer_dir_file_exit - m_last_stats.n_drops_buffer_dir_file_exit;
delta.n_drops_buffer_other_interest_enter = stats.n_drops_buffer_other_interest_enter - m_last_stats.n_drops_buffer_other_interest_enter;
delta.n_drops_buffer_other_interest_exit = stats.n_drops_buffer_other_interest_exit - m_last_stats.n_drops_buffer_other_interest_exit;
delta.n_drops_buffer_close_exit = stats.n_drops_buffer_close_exit - m_last_stats.n_drops_buffer_close_exit;
delta.n_drops_buffer_proc_exit = stats.n_drops_buffer_proc_exit - m_last_stats.n_drops_buffer_proc_exit;
delta.n_drops_scratch_map = stats.n_drops_scratch_map - m_last_stats.n_drops_scratch_map;
delta.n_drops_pf = stats.n_drops_pf - m_last_stats.n_drops_pf;
delta.n_drops_bug = stats.n_drops_bug - m_last_stats.n_drops_bug;
@@ -118,7 +120,7 @@ bool syscall_evt_drop_mgr::process_event(std::shared_ptr<sinsp> inspector, sinsp
{
m_num_actions++;
return perform_actions(evt->get_ts(), delta, inspector->check_current_engine(BPF_ENGINE));
return perform_actions(evt->get_ts(), delta, inspector->check_current_engine(BPF_ENGINE) || inspector->check_current_engine(MODERN_BPF_ENGINE));
}
else
{
@@ -183,6 +185,8 @@ bool syscall_evt_drop_mgr::perform_actions(uint64_t now, scap_stats &delta, bool
*/
output_fields["n_drops_buffer_other_interest_enter"] = std::to_string(delta.n_drops_buffer_other_interest_enter);
output_fields["n_drops_buffer_other_interest_exit"] = std::to_string(delta.n_drops_buffer_other_interest_exit);
output_fields["n_drops_buffer_close_exit"] = std::to_string(delta.n_drops_buffer_close_exit);
output_fields["n_drops_buffer_proc_exit"] = std::to_string(delta.n_drops_buffer_proc_exit);
output_fields["n_drops_scratch_map"] = std::to_string(delta.n_drops_scratch_map); /* Number of kernel side scratch map drops. */
output_fields["n_drops_page_faults"] = std::to_string(delta.n_drops_pf); /* Number of kernel side page faults drops (invalid memory access). */
output_fields["n_drops_bug"] = std::to_string(delta.n_drops_bug); /* Number of kernel side bug drops (invalid condition in the kernel instrumentation). */

View File

@@ -26,8 +26,7 @@ limitations under the License.
static void display_fatal_err(const std::string &&msg)
{
/**
* If stderr logging is not enabled, also log to stderr. When
* daemonized this will simply write to /dev/null.
* If stderr logging is not enabled, also log to stderr.
*/
if (! falco_logger::log_stderr)
{

View File

@@ -14,12 +14,11 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef MINIMAL_BUILD
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
#include <google/protobuf/util/time_util.h>
#endif
#include "falco_outputs.h"
#include "config_falco.h"
#include "formats.h"
@@ -30,7 +29,7 @@ limitations under the License.
#include "outputs_program.h"
#include "outputs_stdout.h"
#include "outputs_syslog.h"
#ifndef MINIMAL_BUILD
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
#include "outputs_http.h"
#include "outputs_grpc.h"
#endif
@@ -47,6 +46,8 @@ falco_outputs::falco_outputs(
bool json_include_tags_property,
uint32_t timeout,
bool buffered,
size_t outputs_queue_capacity,
falco_common::outputs_queue_recovery_type outputs_queue_recovery,
bool time_format_iso_8601,
const std::string& hostname)
{
@@ -64,13 +65,19 @@ falco_outputs::falco_outputs(
{
add_output(output);
}
m_outputs_queue_num_drops = {0};
m_outputs_queue_recovery = outputs_queue_recovery;
#ifndef __EMSCRIPTEN__
m_queue.set_capacity(outputs_queue_capacity);
m_worker_thread = std::thread(&falco_outputs::worker, this);
#endif
}
falco_outputs::~falco_outputs()
{
#ifndef __EMSCRIPTEN__
this->stop_worker();
#endif
for(auto o : m_outputs)
{
delete o;
@@ -98,7 +105,7 @@ void falco_outputs::add_output(falco::outputs::config oc)
{
oo = new falco::outputs::output_syslog();
}
#ifndef MINIMAL_BUILD
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
else if(oc.name == "http")
{
oo = new falco::outputs::output_http();
@@ -113,8 +120,16 @@ void falco_outputs::add_output(falco::outputs::config oc)
throw falco_exception("Output not supported: " + oc.name);
}
oo->init(oc, m_buffered, m_hostname, m_json_output);
m_outputs.push_back(oo);
std::string init_err;
if (oo->init(oc, m_buffered, m_hostname, m_json_output, init_err))
{
m_outputs.push_back(oo);
}
else
{
falco_logger::log(LOG_ERR, "Failed to init output: " + init_err);
delete(oo);
}
}
void falco_outputs::handle_event(gen_event *evt, std::string &rule, std::string &source,
@@ -245,7 +260,9 @@ void falco_outputs::stop_worker()
watchdog<void *> wd;
wd.start([&](void *) -> void {
falco_logger::log(LOG_NOTICE, "output channels still blocked, discarding all remaining notifications\n");
#ifndef __EMSCRIPTEN__
m_queue.clear();
#endif
this->push_ctrl(falco_outputs::ctrl_msg_type::CTRL_MSG_STOP);
});
wd.set_timeout(m_timeout, nullptr);
@@ -266,11 +283,35 @@ inline void falco_outputs::push_ctrl(ctrl_msg_type cmt)
inline void falco_outputs::push(const ctrl_msg& cmsg)
{
#ifndef __EMSCRIPTEN__
if (!m_queue.try_push(cmsg))
{
fprintf(stderr, "Fatal error: Output queue reached maximum capacity. Exiting.\n");
exit(EXIT_FAILURE);
switch (m_outputs_queue_recovery)
{
case falco_common::RECOVERY_EXIT:
falco_logger::log(LOG_ERR, "Fatal error: Output queue out of memory. Exiting ...");
exit(EXIT_FAILURE);
case falco_common::RECOVERY_EMPTY:
m_outputs_queue_num_drops += m_queue.size() + 1;
falco_logger::log(LOG_ERR, "Output queue out of memory. Drop event plus events in queue due to emptying the queue; continue on ...");
m_queue.empty();
break;
case falco_common::RECOVERY_CONTINUE:
m_outputs_queue_num_drops++;
falco_logger::log(LOG_ERR, "Output queue out of memory. Drop event and continue on ...");
break;
default:
falco_logger::log(LOG_ERR, "Fatal error: strategy unknown. Exiting ...");
exit(EXIT_FAILURE);
break;
}
}
#else
for (auto o : m_outputs)
{
process_msg(o, cmsg);
}
#endif
}
// todo(leogr,leodido): this function is not supposed to throw exceptions, and with "noexcept",
@@ -289,28 +330,16 @@ void falco_outputs::worker() noexcept
do
{
// Block until a message becomes available.
#ifndef __EMSCRIPTEN__
m_queue.pop(cmsg);
#endif
for(const auto o : m_outputs)
for(auto o : m_outputs)
{
wd.set_timeout(timeout, o->get_name());
try
{
switch(cmsg.type)
{
case ctrl_msg_type::CTRL_MSG_OUTPUT:
o->output(&cmsg);
break;
case ctrl_msg_type::CTRL_MSG_CLEANUP:
case ctrl_msg_type::CTRL_MSG_STOP:
o->cleanup();
break;
case ctrl_msg_type::CTRL_MSG_REOPEN:
o->reopen();
break;
default:
falco_logger::log(LOG_DEBUG, "Outputs worker received an unknown message type\n");
}
process_msg(o, cmsg);
}
catch(const std::exception &e)
{
@@ -320,3 +349,27 @@ void falco_outputs::worker() noexcept
wd.cancel_timeout();
} while(cmsg.type != ctrl_msg_type::CTRL_MSG_STOP);
}
inline void falco_outputs::process_msg(falco::outputs::abstract_output* o, const ctrl_msg& cmsg)
{
switch(cmsg.type)
{
case ctrl_msg_type::CTRL_MSG_OUTPUT:
o->output(&cmsg);
break;
case ctrl_msg_type::CTRL_MSG_CLEANUP:
case ctrl_msg_type::CTRL_MSG_STOP:
o->cleanup();
break;
case ctrl_msg_type::CTRL_MSG_REOPEN:
o->reopen();
break;
default:
falco_logger::log(LOG_DEBUG, "Outputs worker received an unknown message type\n");
}
}
uint64_t falco_outputs::get_outputs_queue_num_drops()
{
return m_outputs_queue_num_drops.load();
}

View File

@@ -24,7 +24,9 @@ limitations under the License.
#include "falco_engine.h"
#include "outputs.h"
#include "formats.h"
#ifndef __EMSCRIPTEN__
#include "tbb/concurrent_queue.h"
#endif
/*!
\brief This class acts as the primary interface between a program and the
@@ -46,6 +48,8 @@ public:
bool json_include_tags_property,
uint32_t timeout,
bool buffered,
size_t outputs_queue_capacity,
falco_common::outputs_queue_recovery_type outputs_queue_recovery,
bool time_format_iso_8601,
const std::string& hostname);
@@ -81,6 +85,12 @@ public:
*/
void reopen_outputs();
/*!
\brief Return the number of currently dropped events as a result of failed push attempts
into the outputs queue when using `continue` or `empty` recovery strategies.
*/
uint64_t get_outputs_queue_num_drops();
private:
std::unique_ptr<falco_formats> m_formats;
@@ -105,14 +115,18 @@ private:
ctrl_msg_type type;
};
#ifndef __EMSCRIPTEN__
typedef tbb::concurrent_bounded_queue<ctrl_msg> falco_outputs_cbq;
falco_outputs_cbq m_queue;
#endif
falco_common::outputs_queue_recovery_type m_outputs_queue_recovery;
std::atomic<uint64_t> m_outputs_queue_num_drops;
std::thread m_worker_thread;
inline void push(const ctrl_msg& cmsg);
inline void push_ctrl(ctrl_msg_type cmt);
void worker() noexcept;
void stop_worker();
void add_output(falco::outputs::config oc);
inline void process_msg(falco::outputs::abstract_output* o, const ctrl_msg& cmsg);
};

View File

@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
#include <memory>
#include <mutex>
#include <condition_variable>

View File

@@ -62,14 +62,17 @@ struct message
class abstract_output
{
public:
virtual ~abstract_output() {}
virtual ~abstract_output() = default;
void init(const config& oc, bool buffered, const std::string& hostname, bool json_output)
virtual bool init(const config& oc, bool buffered, const std::string& hostname, bool json_output, std::string &err)
{
m_oc = oc;
m_buffered = buffered;
m_hostname = hostname;
m_json_output = json_output;
err = "";
return true;
}
// Return the output's name as per its configuration.

View File

@@ -18,91 +18,107 @@ limitations under the License.
#include "logger.h"
#include "banned.h" // This raises a compilation error when certain functions are used
#define CHECK_RES(fn) res = res == CURLE_OK ? fn : res
static size_t noop_write_callback(void *contents, size_t size, size_t nmemb, void *userp)
{
// We don't want to echo anything. Just return size of bytes ignored
return size * nmemb;
}
bool falco::outputs::output_http::init(const config& oc, bool buffered, const std::string& hostname, bool json_output, std::string &err)
{
if (!falco::outputs::abstract_output::init(oc, buffered, hostname, json_output, err)) {
return false;
}
m_curl = nullptr;
m_http_headers = nullptr;
CURLcode res = CURLE_FAILED_INIT;
m_curl = curl_easy_init();
if(!m_curl)
{
falco_logger::log(LOG_ERR, "libcurl failed to initialize the handle: " + std::string(curl_easy_strerror(res)));
return false;
}
if(m_json_output)
{
m_http_headers = curl_slist_append(m_http_headers, "Content-Type: application/json");
}
else
{
m_http_headers = curl_slist_append(m_http_headers, "Content-Type: text/plain");
}
res = curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, m_http_headers);
// if the URL is quoted the quotes should be removed to satisfy libcurl expected format
std::string unquotedUrl = m_oc.options["url"];
if (!unquotedUrl.empty() && (
(unquotedUrl.front() == '\"' && unquotedUrl.back() == '\"') ||
(unquotedUrl.front() == '\'' && unquotedUrl.back() == '\'')
))
{
unquotedUrl = libsinsp::filter::unescape_str(unquotedUrl);
}
CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_URL, unquotedUrl.c_str()));
CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_USERAGENT, m_oc.options["user_agent"].c_str()));
CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_POSTFIELDSIZE, -1L));
if(m_oc.options["insecure"] == std::string("true"))
{
CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, 0L));
CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYHOST, 0L));
}
if(m_oc.options["mtls"] == std::string("true"))
{
CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_SSLCERT, m_oc.options["client_cert"].c_str()));
CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_SSLKEY, m_oc.options["client_key"].c_str()));
}
if (!m_oc.options["ca_cert"].empty())
{
CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_CAINFO, m_oc.options["ca_cert"].c_str()));
}
else if(!m_oc.options["ca_bundle"].empty())
{
CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_CAINFO, m_oc.options["ca_bundle"].c_str()));
}
else
{
CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_CAPATH, m_oc.options["ca_path"].c_str()));
}
if(m_oc.options["echo"] == std::string("false"))
{
// If echo==true, libcurl defaults to fwrite to stdout, ie: echoing
CHECK_RES(curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, noop_write_callback));
}
if(res != CURLE_OK)
{
err = "libcurl error: " + std::string(curl_easy_strerror(res));
return false;
}
return true;
}
void falco::outputs::output_http::output(const message *msg)
{
CURL *curl = NULL;
CURLcode res = CURLE_FAILED_INIT;
struct curl_slist *slist1;
slist1 = NULL;
curl = curl_easy_init();
if(curl)
CURLcode res = curl_easy_setopt(m_curl, CURLOPT_POSTFIELDS, msg->msg.c_str());
CHECK_RES(curl_easy_perform(m_curl));
if(res != CURLE_OK)
{
if (m_json_output)
{
slist1 = curl_slist_append(slist1, "Content-Type: application/json");
} else {
slist1 = curl_slist_append(slist1, "Content-Type: text/plain");
}
res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
if(res == CURLE_OK)
{
// if the URL is quoted the quotes should be removed to satisfy libcurl expected format
std::string unquotedUrl = m_oc.options["url"];
if (!unquotedUrl.empty() && (
(unquotedUrl.front() == '\"' && unquotedUrl.back() == '\"') ||
(unquotedUrl.front() == '\'' && unquotedUrl.back() == '\'')
))
{
unquotedUrl = libsinsp::filter::unescape_str(unquotedUrl);
}
res = curl_easy_setopt(curl, CURLOPT_URL, unquotedUrl.c_str());
}
if(res == CURLE_OK)
{
res = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, msg->msg.c_str());
}
if(res == CURLE_OK)
{
res = curl_easy_setopt(curl, CURLOPT_USERAGENT, m_oc.options["user_agent"].c_str());
}
if(res == CURLE_OK)
{
res = curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, -1L);
}
if(res == CURLE_OK)
{
if(m_oc.options["insecure"] == std::string("true"))
{
res = curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER, 0L);
if(res == CURLE_OK)
{
res = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
}
}
}
if(res == CURLE_OK)
{
if (!m_oc.options["ca_cert"].empty())
{
res = curl_easy_setopt(curl, CURLOPT_CAINFO, m_oc.options["ca_cert"].c_str());
}else if(!m_oc.options["ca_bundle"].empty())
{
res = curl_easy_setopt(curl, CURLOPT_CAINFO, m_oc.options["ca_bundle"].c_str());
}else{
res = curl_easy_setopt(curl, CURLOPT_CAPATH, m_oc.options["ca_path"].c_str());
}
}
if(res == CURLE_OK)
{
res = curl_easy_perform(curl);
}
if(res != CURLE_OK)
{
falco_logger::log(LOG_ERR, "libcurl error: " + std::string(curl_easy_strerror(res)));
}
curl_easy_cleanup(curl);
curl = NULL;
curl_slist_free_all(slist1);
slist1 = NULL;
falco_logger::log(LOG_ERR, "libcurl failed to perform call: " + std::string(curl_easy_strerror(res)));
}
}
void falco::outputs::output_http::cleanup()
{
curl_easy_cleanup(m_curl);
m_curl = nullptr;
curl_slist_free_all(m_http_headers);
m_http_headers = nullptr;
}

View File

@@ -25,7 +25,13 @@ namespace outputs
class output_http : public abstract_output
{
void output(const message *msg);
bool init(const config& oc, bool buffered, const std::string& hostname, bool json_output, std::string &err) override;
void output(const message *msg) override;
void cleanup() override;
private:
CURL *m_curl;
struct curl_slist *m_http_headers;
};
} // namespace outputs

View File

@@ -32,6 +32,7 @@ limitations under the License.
// overflows here. Threads calling stats_writer::handle() will just
// check that this value changed since their last observation.
static std::atomic<stats_writer::ticker_t> s_timer((stats_writer::ticker_t) 0);
static timer_t s_timerid;
static void timer_handler(int signum)
{
@@ -51,25 +52,29 @@ bool stats_writer::init_ticker(uint32_t interval_msec, std::string &err)
return false;
}
timer_t timerid;
struct sigevent sev = {};
/* Create the timer */
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGALRM;
sev.sigev_value.sival_ptr = &timerid;
if (timer_create(CLOCK_MONOTONIC, &sev, &timerid) == -1) {
sev.sigev_value.sival_ptr = &s_timerid;
#ifndef __EMSCRIPTEN__
// delete any previously set timer
timer_delete(s_timerid);
if (timer_create(CLOCK_MONOTONIC, &sev, &s_timerid) == -1) {
err = std::string("Could not create periodic timer: ") + strerror(errno);
return false;
}
#endif
timer.it_value.tv_sec = interval_msec / 1000;
timer.it_value.tv_nsec = (interval_msec % 1000) * 1000 * 1000;
timer.it_interval = timer.it_value;
if (timer_settime(timerid, 0, &timer, NULL) == -1) {
#ifndef __EMSCRIPTEN__
if (timer_settime(s_timerid, 0, &timer, NULL) == -1) {
err = std::string("Could not set up periodic timer: ") + strerror(errno);
return false;
}
#endif
return true;
}
@@ -86,6 +91,11 @@ stats_writer::stats_writer(
m_config = config;
if (config->m_metrics_enabled)
{
/* m_outputs should always be initialized because we use it
* to extract output-queue stats in both cases: rule output and file output.
*/
m_outputs = outputs;
if (!config->m_metrics_output_file.empty())
{
m_file_output.exceptions(std::ofstream::failbit | std::ofstream::badbit);
@@ -95,14 +105,18 @@ stats_writer::stats_writer(
if (config->m_metrics_stats_rule_enabled)
{
m_outputs = outputs;
m_initialized = true;
}
}
if (m_initialized)
{
#ifndef __EMSCRIPTEN__
// capacity and controls should not be relevant for stats outputs, adopt capacity
// for completeness, but do not implement config recovery strategies.
m_queue.set_capacity(config->m_outputs_queue_capacity);
m_worker = std::thread(&stats_writer::worker, this);
#endif
}
}
@@ -110,11 +124,17 @@ stats_writer::~stats_writer()
{
if (m_initialized)
{
#ifndef __EMSCRIPTEN__
stop_worker();
#endif
if (!m_config->m_metrics_output_file.empty())
{
m_file_output.close();
}
// delete timerID and reset timer
#ifndef __EMSCRIPTEN__
timer_delete(s_timerid);
#endif
}
}
@@ -131,17 +151,18 @@ void stats_writer::stop_worker()
inline void stats_writer::push(const stats_writer::msg& m)
{
#ifndef __EMSCRIPTEN__
if (!m_queue.try_push(m))
{
fprintf(stderr, "Fatal error: Stats queue reached maximum capacity. Exiting.\n");
exit(EXIT_FAILURE);
}
#endif
}
void stats_writer::worker() noexcept
{
stats_writer::msg m;
nlohmann::json jmsg;
bool use_outputs = m_config->m_metrics_stats_rule_enabled;
bool use_file = !m_config->m_metrics_output_file.empty();
auto tick = stats_writer::get_ticker();
@@ -151,7 +172,9 @@ void stats_writer::worker() noexcept
while(true)
{
// blocks until a message becomes availables
#ifndef __EMSCRIPTEN__
m_queue.pop(m);
#endif
if (m.stop)
{
return;
@@ -178,6 +201,7 @@ void stats_writer::worker() noexcept
if (use_file)
{
nlohmann::json jmsg;
jmsg["sample"] = m_total_samples;
jmsg["output_fields"] = m.output_fields;
m_file_output << jmsg.dump() << std::endl;
@@ -217,6 +241,7 @@ void stats_writer::collector::get_metrics_output_fields_wrapper(
output_fields["falco.host_boot_ts"] = machine_info->boot_ts_epoch;
output_fields["falco.hostname"] = machine_info->hostname; /* Explicitly add hostname to log msg in case hostname rule output field is disabled. */
output_fields["falco.host_num_cpus"] = machine_info->num_cpus;
output_fields["falco.outputs_queue_num_drops"] = m_writer->m_outputs->get_outputs_queue_num_drops();
output_fields["evt.source"] = src;
for (size_t i = 0; i < sizeof(all_driver_engines) / sizeof(const char*); i++)
@@ -247,7 +272,7 @@ void stats_writer::collector::get_metrics_output_fields_additional(
const scap_agent_info* agent_info = inspector->get_agent_info();
const scap_machine_info* machine_info = inspector->get_machine_info();
#ifndef MINIMAL_BUILD
#if !defined(MINIMAL_BUILD) and !defined(__EMSCRIPTEN__)
/* Resource utilization, CPU and memory usage etc. */
uint32_t nstats = 0;
int32_t rc = 0;

View File

@@ -22,7 +22,9 @@ limitations under the License.
#include <sinsp.h>
#ifndef __EMSCRIPTEN__
#include "tbb/concurrent_queue.h"
#endif
#include "falco_outputs.h"
#include "configuration.h"
@@ -143,7 +145,9 @@ private:
uint64_t m_total_samples;
std::thread m_worker;
std::ofstream m_file_output;
#ifndef __EMSCRIPTEN__
tbb::concurrent_bounded_queue<stats_writer::msg> m_queue;
#endif
std::shared_ptr<falco_outputs> m_outputs;
std::shared_ptr<const falco_configuration> m_config;

View File

@@ -72,6 +72,41 @@ public:
get_node(node, key);
if(node.IsDefined())
{
std::string value = node.as<std::string>();
// Helper function to convert string to the desired type T
auto convert_str_to_t = [&default_value](const std::string& str) -> T {
std::stringstream ss(str);
T result;
if (ss >> result) return result;
return default_value;
};
// If the value starts with `$$`, check for a subsequent `{...}`
if (value.size() >= 3 && value[0] == '$' && value[1] == '$')
{
// If after stripping the first `$`, the string format is like `${VAR}`, treat it as a plain string and don't resolve.
if (value[2] == '{' && value[value.size() - 1] == '}')
{
value = value.substr(1);
return convert_str_to_t(value);
}
else return convert_str_to_t(value);
}
// Check if the value is an environment variable reference
if(value.size() >= 2 && value[0] == '$' && value[1] == '{' && value[value.size() - 1] == '}')
{
// Format: ${ENV_VAR_NAME}
std::string env_var = value.substr(2, value.size() - 3);
const char* env_value = std::getenv(env_var.c_str()); // Get the environment variable value
if(env_value) return convert_str_to_t(env_value);
return default_value;
}
// If it's not an environment variable reference, return the value as is
return node.as<T>();
}
@@ -118,10 +153,10 @@ private:
* The provided key string can navigate the document in its
* nested nodes, with arbitrary depth. The key string follows
* this regular language:
*
*
* Key := NodeKey ('.' NodeKey)*
* NodeKey := (any)+ ('[' (integer)+ ']')*
*
*
* Some examples of accepted key strings:
* - NodeName
* - ListValue[3].subvalue
@@ -146,7 +181,7 @@ private:
if (i > 0 && nodeKey.empty() && key[i - 1] != '.')
{
throw std::runtime_error(
"Parsing error: expected '.' character at pos "
"Parsing error: expected '.' character at pos "
+ std::to_string(i - 1));
}
nodeKey += c;
@@ -157,7 +192,7 @@ private:
if (nodeKey.empty())
{
throw std::runtime_error(
"Parsing error: unexpected character at pos "
"Parsing error: unexpected character at pos "
+ std::to_string(i));
}
ret.reset(ret[nodeKey]);
@@ -181,7 +216,7 @@ private:
throw std::runtime_error("Config error at key \"" + key + "\": " + std::string(e.what()));
}
}
template<typename T>
void get_sequence_from_node(T& ret, const YAML::Node& node) const
{
@@ -250,7 +285,7 @@ namespace YAML {
default:
break;
}
return true;
}
};