Compare commits

..

274 Commits

Author SHA1 Message Date
Andrea Terzolo
baaafa2e60 tmp
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-01-25 16:21:16 +01:00
Melissa Kilby
bb4a643385 update(config): soft deprecation of old stats
add CHANGE NOTICE wrt syscall_event_drops

Co-authored-by: Leonardo Grasso <me@leonardograsso.com>
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-01-25 10:33:15 +01:00
Melissa Kilby
3675587aad cleanup(configs): adjust old stats deprecation notice
Co-authored-by: Andrea Terzolo <andreaterzolo3@gmail.com>
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-01-25 10:33:15 +01:00
Melissa Kilby
8a697502b9 update!(config): add deprecation notice for syscall_event_drops
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-01-25 10:33:15 +01:00
Melissa Kilby
2dc8d452ae fix(userspace/metric): minor fixes in new libsinsp state metrics handling
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-01-24 11:04:13 +01:00
Federico Aponte
8143a194d2 fix: nlohmann_json lib include path
Signed-off-by: Federico Aponte <federico.aponte@sysdig.com>
2024-01-24 09:38:13 +01:00
Jason Dellaluce
acba90d97a test(engine): assess proper list escaping in engine collector
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2024-01-23 11:58:09 +01:00
Jason Dellaluce
ccf62a3745 fix(userspace/engine): avoid storing escaped strings in engine defs
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2024-01-23 11:58:09 +01:00
Federico Di Pierro
10eaf31881 update(cmake): bumped falcoctl to v0.7.1.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-01-23 11:57:09 +01:00
Andrea Terzolo
f4aef006fe chore: bump falco rules
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-01-17 16:20:55 +01:00
Andrea Terzolo
e1c07568b4 chore: bump Falco to libs 0.14.1
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-01-17 15:12:55 +01:00
dependabot[bot]
ded4bdde96 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `2ac430b` to `c39d31a`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](2ac430be13...c39d31a0bc)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-17 09:42:54 +01:00
Andrea Terzolo
ae9ffe414f cleanup: rename none into nodriver
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
Co-authored-by: Leonardo Grasso <me@leonardograsso.com>
2024-01-17 09:41:55 +01:00
Melissa Kilby
d8c368b5ce update(config): graduate outputs_queue to stable
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-01-16 12:54:51 +01:00
Federico Di Pierro
b718083fe7 update(cmake): bump falcoctl to v0.7.0.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-01-12 11:50:39 +01:00
dependabot[bot]
3f4ed4ca4b build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `1221b9e` to `2ac430b`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](1221b9e817...2ac430be13)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-12 00:55:38 +01:00
Andrea Terzolo
a6a1a9769f cleanup: restore the name of a variable
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
Co-authored-by: Luca Guerra <luca.guerra@sysdig.com>
2024-01-11 15:37:38 +01:00
Andrea Terzolo
e601ec2eab chore: bump testing submodule manually to fix e2e tests
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-01-11 15:37:38 +01:00
Andrea Terzolo
64bbffe5ef fix codespell
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-01-11 15:37:38 +01:00
Andrea Terzolo
5ee05abc08 cleanup: adopt a new helper method in tests
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-01-11 15:37:38 +01:00
Andrea Terzolo
c308f5c7e2 cleanup: rename some error messages
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-01-11 15:37:38 +01:00
Andrea Terzolo
ee78c862ad tests: add some new tests on override replace
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-01-11 15:37:38 +01:00
Andrea Terzolo
8ebdbe3e6f cleanup: use macros for default error messages
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-01-11 15:37:38 +01:00
Andrea Terzolo
91d1511285 tests: add test on the order for macro and rules
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-01-11 15:37:38 +01:00
Andrea Terzolo
3f9ede86bb tests: add some new tests about list order
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-01-11 15:37:38 +01:00
Andrea Terzolo
5192921732 doc: typo in the exception
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-01-11 15:37:38 +01:00
Andrea Terzolo
56de6e6786 update(rule_loader): remove the warning on the required_engine_version
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-01-11 15:37:38 +01:00
Andrea Terzolo
f5dea33b5e update(falco): always enable rules warnings
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-01-11 15:37:38 +01:00
Andrea Terzolo
b318c165da cleanup(falco_engine): remove unused methods
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-01-11 15:37:38 +01:00
Andrea Terzolo
5ac005bd4d update(rule_loader): deprecate all non-SemVer compatible values
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-01-11 15:37:38 +01:00
Andrea Terzolo
2367d36867 cleanup(tests): use new check_error_message helper
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-01-11 15:37:38 +01:00
Andrea Terzolo
95e4c58e7f update(rule_loader): deprecate enabled usage
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-01-11 15:37:38 +01:00
Andrea Terzolo
4aebee684a update(rule_loader): deprecate append key and add a warning
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-01-11 15:37:38 +01:00
Andrea Terzolo
63736563a2 cleanup(rule_loader): remove useless include
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-01-11 15:37:38 +01:00
Andrea Terzolo
7cac2833b2 cleanup(rule_loader): add a common log message
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-01-11 15:37:38 +01:00
Federico Di Pierro
447a251e16 chore(ci): bumped rn2md to latest master.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-01-11 09:52:38 +01:00
Federico Di Pierro
b5e64c52f3 fix(ci): manually invoke falcoctl to install cloudtrail and k8saudit plugin before running tests.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-01-11 09:08:38 +01:00
Federico Di Pierro
bbef26aad0 cleanup(cmake): dropped bundled plugins since falcoctl takes care of everything.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-01-11 09:08:38 +01:00
Andrea Terzolo
6bb68c0c43 chore: bump Falco to latest libs
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-01-11 05:32:38 +01:00
dependabot[bot]
a25b5c1045 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `424b258` to `1221b9e`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](424b258789...1221b9e817)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-09 19:01:34 +01:00
Andrea Terzolo
f6ab7f2501 chore: bump driver version
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-01-08 20:20:31 +01:00
Mark Stemm
66df3dc417 Add unit tests for add_source() + related lookup methods
Add unit tests for add_source() and its related find_*_for_source()
methods. The test just verifies that the values provided to
add_source() are the same as the values returned by the find methods.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2024-01-08 12:00:27 +01:00
Mark Stemm
14d1ca3c97 Add methods to look up the factories provided in add_source()
Add methods that allow looking up the factories provided to
add_source(). This allows not having to keep track of the factories
outside of the engine.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2024-01-08 12:00:27 +01:00
Mark Stemm
07d7b9a57a Inline find_source() as it can be called in the event path
Inline find_source as it can be called in the event processing path.

Also take the cached variant that assigns/uses m_syscall_source_idx
and put it in find_source() instead of process_event().

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2024-01-08 12:00:27 +01:00
dependabot[bot]
70ce7b936b build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `cd33bc3` to `424b258`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](cd33bc34af...424b258789)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-05 14:46:18 +01:00
Luca Guerra
728c8d7d0e fix(engine): clarify error message for invalid append
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-12-22 21:49:21 +01:00
Luca Guerra
04dd06b2c6 new(tests): add error testing for rule overrides
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-12-22 21:49:21 +01:00
Luca Guerra
4c023b0d93 update(engine): temporary replace for error messages
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-12-22 21:49:21 +01:00
Luca Guerra
8a7ef687b1 update(engine): throw an error if an unexpected top level key is found in an override
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-12-22 21:49:21 +01:00
Luca Guerra
21c629dc4d chore(engine): bump engine version
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-12-22 21:49:21 +01:00
Luca Guerra
2db29af0e8 update(engine): clarify override error messages
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-12-22 21:49:21 +01:00
Luca Guerra
bc072502cc new(engine): add selective overrides
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-12-22 21:49:21 +01:00
Melissa Kilby
3976e777a5 update(config): clarify deprecation notices + list all env vars
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-12-22 09:55:19 +01:00
Melissa Kilby
9131261ff3 chore: fix some characters in deprecation notices
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-12-22 09:55:19 +01:00
Luca Guerra
e5034323fd cleanup(engine): clarify deprecation notice for engines
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-12-21 17:40:15 +01:00
Federico Di Pierro
213fa392e8 update(cmake): bumped falcoctl to v0.7.0-rc1.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-21 09:35:15 +01:00
Federico Di Pierro
a2c128e934 chore(ci): revert #2961.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-20 12:09:12 +01:00
dependabot[bot]
f2d0c42911 build(deps): Bump submodules/falcosecurity-testing
Bumps [submodules/falcosecurity-testing](https://github.com/falcosecurity/testing) from `930170b` to `9b9630e`.
- [Commits](930170bb0b...9b9630e2d8)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-19 18:46:08 +01:00
Andrea Terzolo
8ff1ef752d chore: bump falco engine version
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-12-18 19:01:01 +01:00
Andrea Terzolo
454882f518 chore: bump Falco to latest libs
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-12-18 19:01:01 +01:00
dependabot[bot]
3c31c05450 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `262f569` to `cd33bc3`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](262f56986e...cd33bc34af)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-18 18:26:01 +01:00
Samuel Gaist
d99c137b09 feat(outputs_http): implement keep alive
Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2023-12-18 17:41:02 +01:00
Samuel Gaist
691bc8b04d feat(outputs_http): implement support for compressed upload
Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2023-12-18 17:41:02 +01:00
Mark Stemm
ab0133d1dd Add unit tests for enabling/disabling rules
Add unit tests for enabling/disabling rules, covering:

 - matching names by substring
 - using "" to match all rules
 - matching names exactly
 - using ruleset ids in addition to ruleset names

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2023-12-18 15:58:04 +01:00
Mark Stemm
334302e525 Allow enabling rules by ruleset id in addition to name
Add alternate enable_* methods that allow enabling rulesets by ruleset
id in addition to name. This might be used by some filter_rulesets to
enable/disable rules on the fly via the falco engine.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2023-12-18 15:58:04 +01:00
Federico Di Pierro
1ab4e9e0fc chore(ci): enable aarch64 falco driver loader tests.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-18 15:26:02 +01:00
Federico Di Pierro
9e1e68f64b chore(unit_tests): added more tests for yaml env vars expansion.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-14 12:44:47 +01:00
Federico Di Pierro
752e8bf16c chore(falco.yaml): use HOME env var for ebpf probe path.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-13 17:45:45 +01:00
Federico Di Pierro
cbbcb61153 new(unit_tests,userspace): properly support env var expansions in all scalar values of yaml file.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-13 17:03:46 +01:00
Federico Di Pierro
3b095a5eda chore(unit_tests): added tests around empty config value resolving to default.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-13 17:03:46 +01:00
Federico Di Pierro
7805bf5ad5 fix(userspace,unit_tests): fixed bool parsing.
Moreover, added some more tests around env vars.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-13 17:03:46 +01:00
Federico Di Pierro
0c0fb63008 chore(unit_test,userspace): allow env var to get expanded in yaml even when part of a string.
Moreover, support env variable embedding another env variable.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-13 17:03:46 +01:00
Andrea Terzolo
ed346e90cd update(falco): bump engine version and checksum
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-12-13 16:59:46 +01:00
Andrea Terzolo
b190a60da7 chore: bump to latest libs commit
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-12-13 16:59:46 +01:00
Andrea Terzolo
34a896f3a5 new(.gitignore): ignore local CMakeUserPresets.json
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-12-13 16:59:46 +01:00
dependabot[bot]
1a338e1a39 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `dd38952` to `262f569`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](dd38952168...262f56986e)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-13 16:01:46 +01:00
Luca Guerra
e3f54a14a6 update(readme): add actuated.dev badge
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-12-12 18:56:44 +01:00
Nitro Cao
4bfc42eb7d feat(falco): monitor events with more types for rules directory
Signed-off-by: Nitro Cao <jaycecao520@gmail.com>
2023-12-12 18:49:44 +01:00
Federico Di Pierro
47959abfed chore(docker): improve usage helper message.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-12 18:23:44 +01:00
Federico Di Pierro
8db79da647 chore(cmake,docker): bumped falcoctl to v0.7.0-beta5.
Moreover, small fix in docker images entrypoints regarding the name printed in usage.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-12 18:23:44 +01:00
dependabot[bot]
9c01f3518a build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `64e2adb` to `dd38952`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](64e2adb309...dd38952168)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-12 14:37:43 +01:00
Federico Di Pierro
f2ebdfaf8e fix(docker): small fixes in docker entrypoints for new driver loader.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-12 09:56:42 +01:00
Federico Aponte
e427c800f3 chore(build): fix error using find_package with ExternalProject_Add
Signed-off-by: Federico Aponte <federico.aponte@sysdig.com>
2023-12-11 16:52:39 +01:00
Federico Aponte
5e17ba6c23 chore(build): allow usage of non-bundled nlohmann-json
Signed-off-by: Federico Aponte <federico.aponte@sysdig.com>
2023-12-11 16:52:39 +01:00
Federico Di Pierro
e177898d2b update(cmake): bumped falcoctl to v0.7.0-beta4.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-11 16:37:39 +01:00
Federico Di Pierro
2dfd687912 update(submodules): bumped falcosecurity/testing to latest master.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-11 16:37:39 +01:00
Federico Di Pierro
b7538429b8 update(cmake): bumped falcoctl to v0.7.0-beta3.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-11 16:37:39 +01:00
Federico Di Pierro
1de6f10ad6 update(cmake): bump falcoctl to 0.7.0-beta2.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-11 16:37:39 +01:00
Federico Di Pierro
5f59fee54f update(submodules): bumped falcosecurity-testing to latest dev.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-11 16:37:39 +01:00
Federico Di Pierro
4d566b2c71 chore(cmake): bumped falcoctl to v0.7.0-beta1.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-11 16:37:39 +01:00
Federico Di Pierro
96f50ddac5 chore(scripts): integrate back master changes FALCO_DRIVER_CHOICE and FALCOCTL_ENABLED .
Also, env variables always have precedence over dialog (ie: if they are set, we always skip dialog).

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-11 16:37:39 +01:00
Federico Di Pierro
ade27c2546 chore(scripts): use new default value for falcoctl driver.host-root config key.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-11 16:37:39 +01:00
Federico Di Pierro
2244cc6f71 update(cmake): bump falcoctl to v0.7.0-alpha2.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-11 16:37:39 +01:00
Federico Di Pierro
1dd47668dd chore(scripts): only configure falcoctl driver type when a driver is selected.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-11 16:37:39 +01:00
Federico Di Pierro
5eb2ae8d76 chore(cmake/modules): bumped falcoctl to latest alpha.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-11 16:37:39 +01:00
Federico Di Pierro
33451cf0bc fix(scripts): fixed driver names for new falcoctl/Falco naming.
But keep old systemd units names to avoid a breaking change.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-11 16:37:39 +01:00
Federico Di Pierro
27161bb508 chore(scripts/systemd): properly make use of new config keys in systemd units.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-11 16:37:39 +01:00
Federico Di Pierro
0c9538241d chore(docker): cleaned up useless removal of falcoctl.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>

Co-authored-by: Leonardo Grasso <me@leonardograsso.com>
2023-12-11 16:37:39 +01:00
Federico Di Pierro
7452c5dc98 chore(cmake): bumped falcoctl to dev from https://github.com/falcosecurity/falcoctl/pull/343.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-11 16:37:39 +01:00
Federico Di Pierro
be100f7ad5 new(docker,scripts): dropped falco-driver-loader in favor of new falcoctl driver command.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-11 16:37:39 +01:00
Luca Guerra
8cf9b35b0e new(ci): run CI jobs on ARM64
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-12-07 18:26:28 +01:00
Luca Guerra
6e4ccb0007 update(ci): enable actuated.dev
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-12-07 18:26:28 +01:00
Federico Aponte
44b7352180 cleanup: fix several warnings from a Clang build
Signed-off-by: Federico Aponte <federico.aponte@sysdig.com>
2023-12-06 16:40:26 +01:00
Vicente J. Jiménez Miras
13991f1ea7 Add use of FALCO_DRIVER_CHOICE and FALCOCTL_ENABLED env vars
Signed-off-by: Vicente J. Jiménez Miras <vjjmiras@gmail.com>
2023-12-06 10:13:25 +01:00
Andrea Terzolo
10226a6c87 chore(falco): bump libs to 000d576ef877cb115cbb56f97187a1d62221e2bd
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-12-06 10:08:25 +01:00
Federico Aponte
e558c4f5a5 chore(build): remove outdated development libs
Signed-off-by: Federico Aponte <federico.aponte@sysdig.com>
2023-12-06 05:46:25 +01:00
Federico Di Pierro
0ba0dd8671 chore(docker/falco): add back some deps to falco docker image.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-12-05 18:34:26 +01:00
Jason Dellaluce
305ed75268 update(submodules): bump falcosecurity-testing
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-12-02 09:38:15 +01:00
Jason Dellaluce
390a13bd40 update(userspace): optimizations in validation and description steps
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-12-02 09:38:15 +01:00
Jason Dellaluce
67542ec88e new(userspace/falco): support -L when validating for parity
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-12-02 09:38:15 +01:00
Jason Dellaluce
e3943ccac3 refactor(userspace/engine): uniform json lib in rules description and not print from engine
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-12-02 09:38:15 +01:00
dependabot[bot]
95968defa5 build(deps): Bump submodules/falcosecurity-testing
Bumps [submodules/falcosecurity-testing](https://github.com/falcosecurity/testing) from `92c313f` to `5248e6d`.
- [Commits](92c313f5ca...5248e6dff9)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-01 13:12:12 +01:00
Luca Guerra
6411eed4a7 cleanup(falco): remove decode_uri as it is no longer used
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-11-29 17:42:06 +01:00
Andrea Terzolo
c5364be191 new: print system info when Falco starts
Print kernel info when Falco starts with a kernel driver

Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-11-28 22:14:05 +01:00
Luca Guerra
ce4d28ef90 chore(falco): update to libs on nov 28th
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-11-28 17:14:04 +01:00
Melissa Kilby
3b068919d0 update(cmake): bump libs and driver to c2fd308 plus bump falco engine version
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-11-28 12:57:04 +01:00
Melissa Kilby
3e4566e5af cleanup(userspace/falco): minor adjustments to stats writer and rebase correction
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-11-28 12:57:04 +01:00
Melissa Kilby
9cb4c09500 cleanup(userspace/falco): enable sinsp_stats_v2
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-11-28 12:57:04 +01:00
Melissa Kilby
8196ee3b83 cleanup(libsinsp): simplify metrics flags config handling
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-11-28 12:57:04 +01:00
Melissa Kilby
af7192bdc3 update(userspace/falco): add libsinsp state metrics option
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-11-28 12:57:04 +01:00
Andrea Terzolo
00b7c56d54 cleanup: rename modern-ebpf into modern_ebpf
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-11-27 15:01:00 +01:00
Andrea Terzolo
2ce8fe9011 docs: improve a log
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-11-27 15:01:00 +01:00
Andrea Terzolo
4443e9d64f fix: fix some broken tests
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-11-27 15:01:00 +01:00
Andrea Terzolo
249ccf2f4b new: add some deprecation warnings
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-11-27 15:01:00 +01:00
Andrea Terzolo
715db9ddb4 cleanup: move some macros inside a shared file
These macros will be used by other files so we need to share them

Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-11-27 15:01:00 +01:00
Federico Di Pierro
0368de5229 chore(userspace): small round of review-induced fixes.
Also, properly warn the user that deprecated CLI options will be ignored
when the new `engine` configuration key is in use.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-11-27 15:01:00 +01:00
Federico Di Pierro
b92e0d6134 chore(userspace,unit_tests): renamed engine.replay.trace_file to engine.replay.capture_file.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-11-27 15:01:00 +01:00
Andrea Terzolo
898ba68b3b test: don't test load config if we are under wasm
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-11-27 15:01:00 +01:00
Andrea Terzolo
96f474a29c docs: fix codespell
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-11-27 15:01:00 +01:00
Andrea Terzolo
12122729a4 docs: add a comment on missing config files
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-11-27 15:01:00 +01:00
Andrea Terzolo
335022076f docs: fix some docs
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-11-27 15:01:00 +01:00
Andrea Terzolo
1b14fed380 tests: call the callback action only once
moreover this commit corrects `cpus_for_each_syscall_buffer` into test
configs

Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-11-27 15:01:00 +01:00
Andrea Terzolo
11253cc0eb docs: add some descriptions in falco.yaml
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-11-27 15:01:00 +01:00
Andrea Terzolo
be16af7fe0 cleanup: rename cpus_for_each_syscall_buffer
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-11-27 15:01:00 +01:00
Andrea Terzolo
588a94578a fix: take into consideration that load_yaml is called more than once
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-11-27 15:01:00 +01:00
Andrea Terzolo
5e8e0a4722 new: allow to use only one between the config and the command line
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-11-27 15:01:00 +01:00
Andrea Terzolo
bfef0e95be fix: use drop_failed_exit instead of just drop_failed
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-11-27 15:01:00 +01:00
Andrea Terzolo
bc8f61ca68 tests: add a basic test to check config precedence
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-11-27 15:01:00 +01:00
Andrea Terzolo
2778b12344 fix: always initialize the engine configs
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-11-27 15:01:00 +01:00
Federico Di Pierro
7056cb9035 chore(userspace): properly let old config keys override new ones when set to a non-default value.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>

Co-authored-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-11-27 15:01:00 +01:00
Andrea Terzolo
1f27f3b7f0 cleanup: move some initializations and add helpers
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-11-27 15:01:00 +01:00
Andrea Terzolo
1ee6569a5d fix: use only new config instead of old command line options
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-11-27 15:01:00 +01:00
Andrea Terzolo
f3f56db5ca cleanup: some renaming from bpf to ebpf
the idea is to use only the word `ebpf` in Falco

Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-11-27 15:01:00 +01:00
Federico Di Pierro
4127764129 chore(userspace): renamed driver. config to engine.; renamed engine.replay.scap_file to engine.replay.trace_file.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-11-27 15:01:00 +01:00
Federico Di Pierro
4f1b950e0d chore(userspace,falco.yaml): rename new config key to driver.kind.
Moreover, renamed driver kinds to use better naming, and move driver's related
config keys under `driver.$kind`.

Added DEPRECTATION notices on CLI options, and in falco.yaml.

DEPRECATED options (both CLI and config ones) will have priority over the new ones,
to retain compatibility with existing configs.

DEPRECATED options will be dropped in Falco 0.38.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>

Co-authored-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-11-27 15:01:00 +01:00
Roberto Scolaro
626e609e4b new(userspace/falco): select driver from config
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-27 15:01:00 +01:00
Roberto Scolaro
ea2d62d56b new(falco.yaml): added driver selection section
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-27 15:01:00 +01:00
Roberto Scolaro
fb4ac046b0 refacotr(configuration): enhance readability of get_driver_mode
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-27 15:01:00 +01:00
Roberto Scolaro
d53fa930c2 wip: driver selection in falco.yaml
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-27 15:01:00 +01:00
Richard Tweed
5dc9987877 update(doc): Add Thought Machine as adopters
Signed-off-by: Richard Tweed <RichardoC@users.noreply.github.com>

Signed-off-by: Richard Tweed <RichardoC@users.noreply.github.com>
2023-11-22 14:31:42 +01:00
Andrea Terzolo
a1d5bb7009 cleanup: remove init in the configuration constructor
This `init({});` in the falco_configuration constructor is unnecessary
since when we call the action `load_config`, if we don't have a config
file, we will call the same `init` we have just removed. This cleanup
avoids calling `falco_configuration::init` 2 times.

Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-11-21 15:44:39 +01:00
Jason Dellaluce
66a122d4ce update(userspace/engine): bump engine version
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-11-16 09:26:19 +01:00
Jason Dellaluce
b3775ce91c update(cmake): bump driver to latest
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-11-16 09:26:19 +01:00
Jason Dellaluce
1e3f17150d cleanup(falco.yaml): remove config docs and options about k8s metadata
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-11-16 09:26:19 +01:00
Jason Dellaluce
04e2f19915 refactor: solve compilation issues with latest libs changes
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-11-16 09:26:19 +01:00
Jason Dellaluce
ef816e8b06 update(cmake): bump libs to latest
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-11-16 09:26:19 +01:00
dependabot[bot]
2bcd12755f build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `8f0520f` to `64e2adb`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](8f0520fa09...64e2adb309)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-16 09:25:19 +01:00
Jason Dellaluce
359bd6e593 cleanup(userspace/engine): remove legacy k8saudit implementation
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-11-15 16:05:15 +01:00
Luca Guerra
f073a6ee88 update(engine): add tests for decode_url()
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-11-14 20:36:15 +01:00
Luca Guerra
8bf40cdf88 update(engine): port decode_uri in falco engine
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-11-14 20:36:15 +01:00
Luca Guerra
22cc2e5add fix(gha): disable branch protection rule trigger for scorecard
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-11-14 15:19:13 +01:00
Roberto Scolaro
92b42c9474 fix(userspace/falco): fix create_dir behaviour
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-13 10:59:47 +01:00
Roberto Scolaro
fde8da0e5c fix(userspace/falco): split init_ticker for different oses
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-13 10:59:47 +01:00
Roberto Scolaro
be90768b0a fix(userspace/falco): rename get_sysinfo
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-13 10:59:47 +01:00
Roberto Scolaro
b9d7eb7ab3 refactor(cmake): selectively remove sources on win32
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-13 10:59:47 +01:00
Roberto Scolaro
115729a86a fix(unit_test): new macro for env var setting
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-13 10:59:47 +01:00
Roberto Scolaro
1b8525bf80 refactor(cmake): move compiler flags in another file
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-13 10:59:47 +01:00
Roberto Scolaro
6d4006a1ec feat(ci): create win32 and macos installer
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-13 10:59:47 +01:00
Roberto Scolaro
f0d2f17c8d fix(userspace/falco): include windows.h in print actions
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-13 10:59:47 +01:00
Roberto Scolaro
907ced9f50 refactor(userspace/falco): add log level enum
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-13 10:59:47 +01:00
Roberto Scolaro
df4e91476f chore(userspace/falco/app/actions): refactor sysinfo function
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-13 10:59:47 +01:00
Roberto Scolaro
29d3173ae3 feat(ci): add experimental other platforms support
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>

wip

Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-13 10:59:47 +01:00
Roberto Scolaro
5db29f4692 fix(unit_tests/falco): enable env test on win32
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-13 10:59:47 +01:00
Roberto Scolaro
0ca5251128 fix(userspace/falco): enable --support on windows
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-13 10:59:47 +01:00
Roberto Scolaro
89e45ced87 fix(userspace/falco): disable sys/select.h on windows
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-13 10:59:47 +01:00
Roberto Scolaro
5ee9ff8c8f fix(userspace/falco): disable program_output on windows
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-13 10:59:47 +01:00
Roberto Scolaro
f7575292c6 fix(userspace/falco): disable sys/time.h+inotify on windows
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-13 10:59:47 +01:00
Roberto Scolaro
af70b4e770 fix(userspace/falco): remove syslog on windows
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-13 10:59:47 +01:00
Roberto Scolaro
00a87234ce fix(userpsace/falco): print page size on windows
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-13 10:59:47 +01:00
Roberto Scolaro
325701ce4f fix(userspace/falco): use std::filesystem
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-13 10:59:47 +01:00
Roberto Scolaro
5b3cb654ff fix(userspace/falco): add PATH_MAX for windows build
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-13 10:59:47 +01:00
Roberto Scolaro
e5e5416ade fix(userspace/falco): substitute syscall_evt_drop_action::IGNORE with DISREGARD
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-13 10:59:47 +01:00
Roberto Scolaro
fb0d757bfe fix(userspace/falco): use io.h instead of unistd.h on win32
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-13 10:59:47 +01:00
Roberto Scolaro
7cf23fb7c6 fix(cmake): include jq only on linux
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-13 10:59:47 +01:00
Roberto Scolaro
345136c6c8 chore(cmake/modules): yaml-cpp bump
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-13 10:59:47 +01:00
Roberto Scolaro
916d571cd0 fix(cmake): various fixes for windows build
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>

Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-13 10:59:47 +01:00
Roberto Scolaro
e0f7c597be fix(build): various fixes for macos build
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-11-13 10:59:47 +01:00
dependabot[bot]
8cfa79fbc8 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `e206c1a` to `8f0520f`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](e206c1a3f1...8f0520fa09)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-09 15:00:27 +01:00
Lorenzo Susini
7319b93d9b update(userspace/falco): introduce new engine_version_semver key in versions endpoint
Signed-off-by: Lorenzo Susini <susinilorenzo1@gmail.com>
2023-11-08 16:30:25 +01:00
Luca Guerra
3e95faac44 chore(gha): set cosign-installer to v3.1.2
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-11-05 06:06:14 +01:00
Samuel Gaist
d074728994 feat(userspace/falco): add configuration support for IPV6 webserver listen address
The IPV6 capabilities is provided through cpp-httplib.

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2023-11-03 09:09:08 +01:00
Samuel Gaist
fac48cd145 test(configuration): implement basic webserver listen address test
Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2023-11-03 09:09:08 +01:00
Samuel Gaist
91a9717779 feat(userspace/falco): implement configuration of webserver listening
address

Currently the webserver is listening on the hard coded 0.0.0.0. This
patch keeps this default but allows the administrator to change it.

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2023-11-03 09:09:08 +01:00
Jason Dellaluce
f5985720f1 fix(userspace/engine): cache latest rules compilation output
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-11-02 20:32:07 +01:00
Jason Dellaluce
2e7cacb4e0 fix(userspace/engine): solve description of macro-only rules
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-11-02 16:16:06 +01:00
Federico Di Pierro
214e41d093 new(docs): add changelog for 0.36.2.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-11-01 18:05:05 +01:00
Massimiliano Giovagnoli
1609ee8559 ci(.github): add ossf scorecard pipeline
Open Source Security Foundation Scorecard [1] is an automated tool
that assesses a number of important checks associated with
software security and assigns each check a score of 0-10.

Also, the OSSF Scorecard is one of the metrics monitored by
the CNCF CLO Monitor [2].

1. https://github.com/ossf/scorecard
2. https://github.com/cncf/clomonitor

Signed-off-by: Massimiliano Giovagnoli <me@maxgio.it>
2023-10-26 19:00:45 +02:00
Luca Guerra
3ff2bb5c2b cleanup(engine): strncpy -> strlcpy
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-10-19 17:41:22 +02:00
Luca Guerra
39aa8fe05f new(ci): add semgrep to check for banned functions
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-10-19 17:41:22 +02:00
Luca Guerra
1e38967b18 update(engine): remove banned.h
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-10-19 17:41:22 +02:00
Roberto Scolaro
b7cef5bab2 fix(userspace/engine): fix memory leak
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2023-10-17 21:20:15 +02:00
Luca Guerra
fec8a825cd update(ci): update setup-go action
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-10-17 16:20:16 +02:00
Luca Guerra
fc35c02015 update(ci): update aws pipeline jobs
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-10-17 16:20:16 +02:00
Luca Guerra
e68bb3be7d update(ci): upgrade docker pipeline jobs
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-10-17 16:20:16 +02:00
Andrea Terzolo
099332f958 new(docs): add changelog for 0.36.1
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-10-16 18:59:10 +02:00
dependabot[bot]
e4054fc5ea build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `a22d0d7` to `e206c1a`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](a22d0d7a41...e206c1a3f1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-12 13:04:46 +02:00
Melissa Kilby
dd807b19c8 feat(userspace): remove experimental outputs queue recovery strategies
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-10-12 13:03:46 +02:00
Gerald Combs
56401340c3 update(doc) Add Wireshark / Logray as adopters
Signed-off-by: Gerald Combs <gerald@wireshark.org>
2023-10-12 11:15:45 +02:00
dependabot[bot]
4b9a8d9388 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `d119706` to `a22d0d7`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](d119706074...a22d0d7a41)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-10 19:21:38 +02:00
Melissa Kilby
32b7ccd8dc cleanup(userspace/falco): reset s_timerid_exists at stats_writer teardown
Co-authored-by: Andrea Terzolo <andreaterzolo3@gmail.com>
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-10-06 15:32:05 +02:00
Melissa Kilby
d28f43cd98 chore: apply codespell fixes
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-10-06 15:32:05 +02:00
Melissa Kilby
943446ba97 cleanup(userspace/falco): add more comments around timer_delete workaround
Co-authored-by: Federico Di Pierro <nierro92@gmail.com>
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-10-06 15:32:05 +02:00
Melissa Kilby
d4a4de9055 fix(userspace/falco): timer_delete() workaround due to bug in older GLIBC
Workaround for older GLIBC versions (< 2.35), where calling timer_delete()
with an invalid timer ID not returned by timer_create() causes a segfault because of
a bug in GLIBC (https://sourceware.org/bugzilla/show_bug.cgi?id=28257).

Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-10-06 15:32:05 +02:00
Luca Guerra
e6d71d2e8e fix(gha): update rpmsign
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-10-05 18:39:00 +02:00
Luca Guerra
a77e2dec10 fix(gha): use fedora instead of centos 7 for package publishing
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-10-05 11:27:58 +02:00
Luca Guerra
f1dec8f444 chore(gha): pin actions with hash, add TODO for upgrades
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-10-03 15:11:54 +02:00
Luca Guerra
27ad4c3aec update(gha): update checkout action to v4
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-10-03 15:11:54 +02:00
dependabot[bot]
28edf94feb build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `c366d5b` to `d119706`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](c366d5bd03...d119706074)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-02 15:53:48 +02:00
Federico Di Pierro
3c93249efb new(ci): properly link libs and driver releases linked to a Falco release.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-29 19:01:22 +02:00
Andrea Terzolo
29d2406414 cleanup(falco)!: remove outputs.rate and outputs.max_burst
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-29 01:47:21 +02:00
Lorenzo Susini
09b1f92267 update(userspace/engine): update falco engine checksum
Signed-off-by: Lorenzo Susini <susinilorenzo1@gmail.com>
2023-09-28 20:05:21 +02:00
Lorenzo Susini
26e421155b update(submodule): update testing submodule
Signed-off-by: Lorenzo Susini <susinilorenzo1@gmail.com>
2023-09-28 20:05:21 +02:00
Lorenzo Susini
155b2009f3 update(cmake): bump libs version to add the new sinsp_version class impl
Signed-off-by: Lorenzo Susini <susinilorenzo1@gmail.com>
2023-09-28 20:05:21 +02:00
Lorenzo Susini
1326ca356e update(userspace/engine): address jasondellaluce comments for maintainability
Signed-off-by: Lorenzo Susini <susinilorenzo1@gmail.com>
2023-09-28 20:05:21 +02:00
Lorenzo Susini
9bbf9716b6 update(userspace/falco): engine version semver in protobuf and versions_info
Signed-off-by: Lorenzo Susini <susinilorenzo1@gmail.com>
2023-09-28 20:05:21 +02:00
Lorenzo Susini
f8cbeaaa9b update(userspace/engine): let the rule loader reader and collector be able to load rules with both numeric and semver string required_engine_version
Signed-off-by: Lorenzo Susini <susinilorenzo1@gmail.com>
2023-09-28 20:05:21 +02:00
Lorenzo Susini
cd6cb14c08 update(userspace/engine): convert engine version to semver string
Signed-off-by: Lorenzo Susini <susinilorenzo1@gmail.com>
2023-09-28 20:05:21 +02:00
Jason Dellaluce
d3e1a1f746 chore(userspace/engine): apply codespell suggestions
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-09-28 12:39:20 +02:00
Jason Dellaluce
aae114c331 refactor(userspace/engine)!: rename some description details outputs
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-09-28 12:39:20 +02:00
Jason Dellaluce
b67ad907a7 fix(userspace/engine): solve issues with filter details resolver
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-09-28 12:39:20 +02:00
Jason Dellaluce
dc264a0577 fix(userspace/engine): solve issues in describing rules/macros/lists
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-09-28 12:39:20 +02:00
Jason Dellaluce
8f411f3d3b refactor(userspace/engine): modularize rules files compilation
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-09-28 12:39:20 +02:00
Jason Dellaluce
cba80a404f fix(userspace/engine): print rules fields with arguments
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-09-28 12:39:20 +02:00
Jason Dellaluce
26bdefae8e update(userspace/engine): support printing plugins used by rules
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-09-28 12:39:20 +02:00
Jason Dellaluce
dce5cac820 update(userspace/engine): find evt names in filter resolver
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-09-28 12:39:20 +02:00
Jason Dellaluce
ab77a5d687 update(userspace/engine): refactor rule describe methods to accept plugins
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-09-28 12:39:20 +02:00
Federico Di Pierro
7c7ec800a6 chore(ci): bumped rn2md to latest master.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-27 11:20:12 +02:00
dependabot[bot]
e0ac9c4142 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `7a7cf24` to `c366d5b`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](7a7cf24f7d...c366d5bd03)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-27 11:00:12 +02:00
Andrea Terzolo
4de74f3963 cleanup(falco)!: remove --userspace support
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-26 16:14:07 +02:00
Luca Guerra
cca1d705c2 fix(docs): 0.36.0 release date
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-26 12:38:07 +02:00
Luca Guerra
bbb8b014c5 update(docs): add changelog for 0.36.0
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-26 12:38:07 +02:00
dependabot[bot]
2571225571 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `77ba57a` to `7a7cf24`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](77ba57ab2c...7a7cf24f7d)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-26 11:10:07 +02:00
Federico Di Pierro
b02898dc4c chore(cmake): bumped libs to 0.13.1.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-25 14:30:05 +02:00
dependabot[bot]
66ece1a9ac build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `69c9be8` to `77ba57a`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](69c9be89d7...77ba57ab2c)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-22 19:36:49 +02:00
Andrea Terzolo
ab6d76e6d2 chore: bump submodule testing to 62edc65
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-22 15:20:49 +02:00
Luca Guerra
260f189028 update(gha): add version for rn2md
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-22 14:34:49 +02:00
dependabot[bot]
1b29389ed4 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `6d3fcf0` to `69c9be8`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](6d3fcf0467...69c9be89d7)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-22 14:27:49 +02:00
Federico Di Pierro
bb92dcfd2f update(cmake): bumped falcoctl to 0.6.2.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-22 13:04:49 +02:00
Federico Di Pierro
0884ca4c6f chore: automatically attach release author to release body.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-22 12:18:49 +02:00
Federico Di Pierro
e836157771 chore(ci): added permissions to release-body job.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-21 21:04:47 +02:00
Federico Di Pierro
086deb9c6d chore(ci): only run release-body for latest releases, and properly override release name.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-21 21:04:47 +02:00
Federico Di Pierro
49adbf6d08 new(ci): autogenerate release body.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-21 21:04:47 +02:00
Andrea Terzolo
16a37e5c2e fix(dockerfile): remove useless CMD
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-21 17:38:47 +02:00
Andrea Terzolo
c5996bd0cf chore: bump libs to the latest tag
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-21 16:53:47 +02:00
Andrea Terzolo
83db0bb4e2 docs: add a warning for metrics
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-21 16:53:47 +02:00
Andrea Terzolo
d61eaeb5fc chore: bump to the latest libs
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-21 16:53:47 +02:00
Luca Guerra
111a76879b update(falco): bundle rules 2.0.0
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-21 16:16:47 +02:00
Leonardo Grasso
fe50ac22ee update: add SPDX license identifier
See https://github.com/falcosecurity/evolution/issues/318

Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-09-21 13:21:47 +02:00
dependabot[bot]
e3e854f016 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `bea364e` to `6d3fcf0`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](bea364ef41...6d3fcf0467)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-21 12:36:47 +02:00
Federico Di Pierro
5ed9dc0c3a update(cmake): bumped plugins to latest stable versions.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-21 10:53:47 +02:00
Andrea Terzolo
2c95fae9eb chore: bump to latest libs
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-19 14:07:33 +02:00
dependabot[bot]
e3e9efa661 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `ee5fb38` to `bea364e`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](ee5fb38eba...bea364ef41)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-19 08:45:41 +02:00
Luca Guerra
9f5e458f92 update(build): update falcoctl to 0.6.1
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-18 16:29:47 +02:00
dependabot[bot]
071910e6dc build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `43580b4` to `ee5fb38`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](43580b4ceb...ee5fb38eba)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-15 10:38:32 +02:00
Federico Di Pierro
cf10d9022e update(cmake): bumped libs to 0.13.0-rc2 and driver to 6.0.1+driver.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-09-14 15:49:27 +02:00
Luca Guerra
60a64ac647 fix(docker): get the driver loader legacy from the right directory
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-13 15:19:40 +02:00
Luca Guerra
e5e7a4761d fix(build): set the right bucket and version for driver legacy
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-13 15:19:40 +02:00
Andrea Terzolo
6bd40f3ea2 cleanup: thrown exceptions and avoid multiple logs
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2023-09-13 11:28:40 +02:00
dependabot[bot]
c9a424d75e build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `c6e01fa` to `43580b4`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](c6e01fa7a5...43580b4ceb)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-13 09:29:39 +02:00
dependabot[bot]
e2b21402ae build(deps): Bump submodules/falcosecurity-testing
Bumps [submodules/falcosecurity-testing](https://github.com/falcosecurity/testing) from `76d1743` to `30c3643`.
- [Commits](76d1743a0a...30c36439fc)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-13 09:28:40 +02:00
Luca Guerra
7b4264918b update(docs): add driver-loader-legacy to readme and fix bad c&p
Signed-off-by: Luca Guerra <luca@guerra.sh>
2023-09-12 13:33:35 +02:00
Jason Dellaluce
5595212ff9 fix(userspace/falco): clearing full output queue
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-09-12 13:19:35 +02:00
dependabot[bot]
fdd520f163 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `d31dbc2` to `c6e01fa`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](d31dbc26ea...c6e01fa7a5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-12 09:16:34 +02:00
Leonardo Grasso
b5e3ef95fe docs: add LICENSE file
This commit creates a copy of https://github.com/falcosecurity/falco/blob/master/COPYING (which is kept for historical reasons) to address the recommendation reported by https://github.com/falcosecurity/evolution/issues/317

Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2023-09-12 09:15:34 +02:00
152 changed files with 5666 additions and 5037 deletions

View File

@@ -1,5 +1,5 @@
![LIBS](https://img.shields.io/badge/LIBS-LIBSVER-yellow)
![DRIVER](https://img.shields.io/badge/DRIVER-DRIVERVER-yellow)
[![LIBS](https://img.shields.io/badge/LIBS-LIBSVER-yellow)](https://github.com/falcosecurity/libs/releases/tag/LIBSVER)
[![DRIVER](https://img.shields.io/badge/DRIVER-DRIVERVER-yellow)](https://github.com/falcosecurity/libs/releases/tag/DRIVERVER)
| Packages | Download |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |

View File

@@ -23,6 +23,13 @@ jobs:
arch: x86_64
version: ${{ needs.fetch-version.outputs.version }}
build-dev-packages-arm64:
needs: [fetch-version]
uses: ./.github/workflows/reusable_build_packages.yaml
with:
arch: aarch64
version: ${{ needs.fetch-version.outputs.version }}
test-dev-packages:
needs: [fetch-version, build-dev-packages]
uses: ./.github/workflows/reusable_test_packages.yaml
@@ -35,6 +42,16 @@ jobs:
static: ${{ matrix.static != '' && true || false }}
version: ${{ needs.fetch-version.outputs.version }}
test-dev-packages-arm64:
needs: [fetch-version, build-dev-packages]
uses: ./.github/workflows/reusable_test_packages.yaml
strategy:
fail-fast: false
with:
arch: aarch64
static: ${{ matrix.static != '' && true || false }}
version: ${{ needs.fetch-version.outputs.version }}
build-dev-minimal:
uses: ./.github/workflows/reusable_build_dev.yaml
with:
@@ -42,7 +59,15 @@ jobs:
git_ref: ${{ github.event.pull_request.head.sha }}
minimal: true
build_type: Debug
build-dev-minimal-arm64:
uses: ./.github/workflows/reusable_build_dev.yaml
with:
arch: aarch64
git_ref: ${{ github.event.pull_request.head.sha }}
minimal: true
build_type: Debug
# builds using system deps, checking out the PR's code
# note: this also runs a command that generates an output of form: "<engine_version> <some_hash>",
# of which <some_hash> is computed by hashing in order the following:
@@ -64,7 +89,7 @@ jobs:
needs: [build-dev]
steps:
- name: Checkout PR head ref
uses: actions/checkout@v3
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
@@ -89,7 +114,7 @@ jobs:
needs: [build-dev]
steps:
- name: Checkout base ref
uses: actions/checkout@v3
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
fetch-depth: 0
ref: ${{ github.base_ref }}
@@ -97,7 +122,10 @@ jobs:
- name: Check Engine version
run: |
base_hash=$(grep CHECKSUM "./userspace/engine/falco_engine_version.h" | awk '{print $3}' | sed -e 's/"//g')
base_engine_ver=$(grep ENGINE_VERSION "./userspace/engine/falco_engine_version.h" | awk '{print $3}' | sed -e 's/(//g' -e 's/)//g')
base_engine_ver_major=$(grep ENGINE_VERSION_MAJOR "./userspace/engine/falco_engine_version.h" | head -n 1 | awk '{print $3}' | sed -e 's/(//g' -e 's/)//g')
base_engine_ver_minor=$(grep ENGINE_VERSION_MINOR "./userspace/engine/falco_engine_version.h" | head -n 1 | awk '{print $3}' | sed -e 's/(//g' -e 's/)//g')
base_engine_ver_patch=$(grep ENGINE_VERSION_PATCH "./userspace/engine/falco_engine_version.h" | head -n 1 | awk '{print $3}' | sed -e 's/(//g' -e 's/)//g')
base_engine_ver="${base_engine_ver_major}.${base_engine_ver_minor}.${base_engine_ver_patch}"
cur_hash=$(echo "${{ needs.build-dev.outputs.cmdout }}" | cut -d ' ' -f 2)
cur_engine_ver=$(echo "${{ needs.build-dev.outputs.cmdout }}" | cut -d ' ' -f 1)

View File

@@ -36,19 +36,19 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
fetch-depth: 0
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
@@ -56,7 +56,7 @@ jobs:
run: sudo apt update -y
- name: Install build dependencies
run: sudo DEBIAN_FRONTEND=noninteractive apt install libssl-dev libyaml-dev libc-ares-dev libprotobuf-dev protobuf-compiler libjq-dev libyaml-cpp-dev libgrpc++-dev protobuf-compiler-grpc rpm libelf-dev cmake build-essential libcurl4-openssl-dev linux-headers-$(uname -r) clang llvm git -y
run: sudo DEBIAN_FRONTEND=noninteractive apt install libssl-dev libc-ares-dev libprotobuf-dev protobuf-compiler libyaml-cpp-dev libgrpc++-dev protobuf-compiler-grpc rpm libelf-dev cmake build-essential libcurl4-openssl-dev linux-headers-$(uname -r) clang llvm git -y
- name: Prepare project
run: |
@@ -72,4 +72,4 @@ jobs:
popd
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9

View File

@@ -5,8 +5,8 @@ jobs:
codespell:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: codespell-project/actions-codespell@master
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- uses: codespell-project/actions-codespell@94259cd8be02ad2903ba34a22d9c13de21a74461 # v2.0
with:
skip: .git
ignore_words_file: .codespellignore

View File

@@ -15,8 +15,8 @@ jobs:
outputs:
engine_version_changed: ${{ steps.filter.outputs.engine_version }}
steps:
- uses: actions/checkout@v2
- uses: dorny/paths-filter@v2
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
id: filter
with:
filters: |
@@ -31,7 +31,7 @@ jobs:
if: needs.paths-filter.outputs.engine_version_changed == 'false'
steps:
- name: Check driver Falco engine version
uses: mshick/add-pr-comment@v2
uses: mshick/add-pr-comment@7c0890544fb33b0bdd2e59467fbacb62e028a096 # v2.8.1
with:
message: |
This PR may bring feature or behavior changes in the Falco engine and may require the engine version to be bumped.

26
.github/workflows/insecure-api.yaml vendored Normal file
View File

@@ -0,0 +1,26 @@
name: Insecure API check
on:
pull_request:
branches:
- master
- 'release/**'
- 'maintainers/**'
jobs:
insecure-api:
name: check-insecure-api
runs-on: ubuntu-latest
container:
image: returntocorp/semgrep:1.41.0@sha256:85956fbe795a0e8a3825d5252f175887c0e0c6ce7a766a07062c0fb68415cd67
steps:
- name: Checkout Falco ⤵️
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
fetch-depth: 0
- name: Scan PR for insecure API usage 🕵️
run: |
semgrep scan \
--error \
--metrics=off \
--baseline-commit ${{ github.event.pull_request.base.sha }} \
--config=./semgrep

View File

@@ -131,7 +131,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Clone repo
uses: actions/checkout@v4
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- name: Extract LIBS and DRIVER versions
run: |
@@ -147,7 +147,7 @@ jobs:
sed -i s/FALCOVER/${{ github.event.release.tag_name }}/g release-body.md
- name: Generate release notes
uses: leodido/rn2md@1a17f0e75758c15128a5146e8af5ca3a47209b3f
uses: leodido/rn2md@1378404a058ecf86701f3ab533d487333fc675a7
with:
milestone: ${{ github.event.release.tag_name }}
output: ./notes.md
@@ -161,7 +161,7 @@ jobs:
echo "#### Release Manager @${{ github.event.release.author.login }}" >> release-body.md
- name: Release
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v0.1.15
with:
body_path: ./release-body.md
tag_name: ${{ github.event.release.tag_name }}

View File

@@ -27,31 +27,30 @@ on:
required: false
default: ''
type: string
jobs:
build-and-test:
# See https://github.com/actions/runner/issues/409#issuecomment-1158849936
runs-on: ${{ (inputs.arch == 'aarch64' && fromJSON('[ "self-hosted", "linux", "ARM64" ]')) || 'ubuntu-22.04' }}
container: ${{ (inputs.arch == 'aarch64' && 'ubuntu:22.04') || '' }}
runs-on: ${{ (inputs.arch == 'aarch64' && 'actuated-arm64-8cpu-16gb') || 'ubuntu-22.04' }}
outputs:
cmdout: ${{ steps.run_cmd.outputs.out }}
cmdout: ${{ steps.run_cmd.outputs.out }}
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
fetch-depth: 0
ref: ${{ inputs.git_ref }}
- name: Update base image
run: sudo apt update -y
- name: Install build dependencies
run: sudo DEBIAN_FRONTEND=noninteractive apt install libjq-dev libelf-dev libyaml-cpp-dev cmake build-essential git -y
run: sudo DEBIAN_FRONTEND=noninteractive apt install libelf-dev libyaml-cpp-dev cmake build-essential git -y
- name: Install build dependencies (non-minimal)
if: inputs.minimal != true
run: sudo DEBIAN_FRONTEND=noninteractive apt install libssl-dev libyaml-dev libc-ares-dev libprotobuf-dev protobuf-compiler libgrpc++-dev protobuf-compiler-grpc rpm libcurl4-openssl-dev linux-headers-$(uname -r) clang llvm -y
run: sudo DEBIAN_FRONTEND=noninteractive apt install libssl-dev libc-ares-dev libprotobuf-dev protobuf-compiler libgrpc++-dev protobuf-compiler-grpc rpm libcurl4-openssl-dev linux-headers-$(uname -r) clang llvm -y
- name: Prepare project
run: |
mkdir build
@@ -74,7 +73,7 @@ jobs:
- name: Run unit tests
run: |
pushd build
sudo ./unit_tests/falco_unit_tests
sudo ./unit_tests/falco_unit_tests
popd
- name: Run command

View File

@@ -27,15 +27,15 @@ on:
jobs:
build-docker:
# See https://github.com/actions/runner/issues/409#issuecomment-1158849936
runs-on: ${{ (inputs.arch == 'aarch64' && fromJSON('[ "self-hosted", "linux", "ARM64" ]')) || 'ubuntu-latest' }}
runs-on: ${{ (inputs.arch == 'aarch64' && 'actuated-arm64-8cpu-16gb') || 'ubuntu-latest' }}
env:
TARGETARCH: ${{ (inputs.arch == 'aarch64' && 'arm64') || 'amd64' }}
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0
- name: Build no-driver image
run: |
@@ -87,7 +87,7 @@ jobs:
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
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: falco-images
path: /tmp/falco-*.tar

View File

@@ -14,7 +14,7 @@ on:
jobs:
build-modern-bpf-skeleton:
# See https://github.com/actions/runner/issues/409#issuecomment-1158849936
runs-on: ${{ (inputs.arch == 'aarch64' && fromJSON('[ "self-hosted", "linux", "ARM64" ]')) || 'ubuntu-latest' }}
runs-on: ${{ (inputs.arch == 'aarch64' && 'actuated-arm64-8cpu-16gb') || 'ubuntu-latest' }}
container: fedora:latest
steps:
# Always install deps before invoking checkout action, to properly perform a full clone.
@@ -23,7 +23,7 @@ jobs:
dnf install -y bpftool ca-certificates cmake make automake gcc gcc-c++ kernel-devel clang git pkg-config autoconf automake libbpf-devel
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- name: Build modern BPF skeleton
run: |
@@ -32,7 +32,7 @@ jobs:
make ProbeSkeleton -j6
- name: Upload skeleton
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: bpf_probe_${{ inputs.arch }}.skel.h
path: skeleton-build/skel_dir/bpf_probe.skel.h
@@ -40,7 +40,7 @@ jobs:
build-packages:
# See https://github.com/actions/runner/issues/409#issuecomment-1158849936
runs-on: ${{ (inputs.arch == 'aarch64' && fromJSON('[ "self-hosted", "linux", "ARM64" ]')) || 'ubuntu-latest' }}
runs-on: ${{ (inputs.arch == 'aarch64' && 'actuated-arm64-8cpu-16gb') || 'ubuntu-latest' }}
needs: [build-modern-bpf-skeleton]
container: centos:7
steps:
@@ -53,10 +53,11 @@ jobs:
yum install -y wget git make m4 rpm-build perl-IPC-Cmd
- name: Checkout
uses: actions/checkout@v3
# It is not possible to upgrade the checkout action to versions >= v4.0.0 because of incompatibilities with centos 7's libc.
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- name: Download skeleton
uses: actions/download-artifact@v3
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: bpf_probe_${{ inputs.arch }}.skel.h
path: /tmp
@@ -97,21 +98,21 @@ jobs:
make package
- name: Upload Falco tar.gz package
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: falco-${{ inputs.version }}-${{ inputs.arch }}.tar.gz
path: |
${{ github.workspace }}/build/falco-*.tar.gz
- name: Upload Falco deb package
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: falco-${{ inputs.version }}-${{ inputs.arch }}.deb
path: |
${{ github.workspace }}/build/falco-*.deb
- name: Upload Falco rpm package
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: falco-${{ inputs.version }}-${{ inputs.arch }}.rpm
path: |
@@ -129,7 +130,7 @@ jobs:
apk add g++ gcc cmake make git bash perl linux-headers autoconf automake m4 libtool elfutils-dev libelf-static patch binutils bpftool clang
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
fetch-depth: 0
@@ -154,7 +155,7 @@ jobs:
mv falco-${{ inputs.version }}-x86_64.tar.gz falco-${{ inputs.version }}-static-x86_64.tar.gz
- name: Upload Falco static package
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: falco-${{ inputs.version }}-static-x86_64.tar.gz
path: |
@@ -171,12 +172,12 @@ jobs:
sudo DEBIAN_FRONTEND=noninteractive apt install cmake build-essential git emscripten -y
- name: Select node version
uses: actions/setup-node@v3
uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
with:
node-version: 14
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
fetch-depth: 0
@@ -210,8 +211,74 @@ jobs:
emmake make -j6 package
- name: Upload Falco WASM package
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: falco-${{ inputs.version }}-wasm.tar.gz
path: |
${{ github.workspace }}/build/falco-${{ inputs.version }}-wasm.tar.gz
build-win32-package:
if: ${{ inputs.arch == 'x86_64' }}
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
fetch-depth: 0
- name: Prepare project
run: |
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DMINIMAL_BUILD=On -DUSE_BUNDLED_DEPS=On -DBUILD_FALCO_UNIT_TESTS=On -DFALCO_VERSION=${{ inputs.version }} ..
- name: Build project
run: |
cmake --build build --target package --config Release
- name: Run unit Tests
run: |
build/unit_tests/Release/falco_unit_tests.exe
- name: Upload Falco win32 installer
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: falco-installer-${{ inputs.version }}-win32.exe
path: build/falco-*.exe
- name: Upload Falco win32 package
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: falco-${{ inputs.version }}-win32.exe
path: |
${{ github.workspace }}/build/userspace/falco/Release/falco.exe
build-macos-package:
if: ${{ inputs.arch == 'x86_64' }}
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
fetch-depth: 0
- name: Prepare project
run: |
mkdir build
cd build
cmake -DMINIMAL_BUILD=On -DUSE_BUNDLED_DEPS=On -DBUILD_FALCO_UNIT_TESTS=On -DFALCO_VERSION=${{ inputs.version }} ..
- name: Build project
run: |
cmake --build build --target package
- name: Run unit Tests
run: |
sudo build/unit_tests/falco_unit_tests
- name: Upload Falco macos package
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: falco-${{ inputs.version }}-macos
path: |
${{ github.workspace }}/build/userspace/falco/falco

View File

@@ -19,7 +19,7 @@ jobs:
version: ${{ steps.store_version.outputs.version }}
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
fetch-depth: 0

View File

@@ -26,10 +26,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0
- name: Download images tarballs
uses: actions/download-artifact@v3
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: falco-images
path: /tmp/falco-images
@@ -39,13 +39,13 @@ jobs:
for img in /tmp/falco-images/falco-*.tar; do docker load --input $img; done
- name: Login to Docker Hub
uses: docker/login-action@v2
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0
with:
username: ${{ secrets.DOCKERHUB_USER }}
password: ${{ secrets.DOCKERHUB_SECRET }}
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1
with:
role-to-assume: "arn:aws:iam::292999226676:role/github_actions-falco-ecr"
aws-region: us-east-1 # The region must be set to us-east-1 in order to access ECR Public.
@@ -57,7 +57,7 @@ jobs:
registry-type: public
- name: Setup Crane
uses: imjasonh/setup-crane@v0.3
uses: imjasonh/setup-crane@00c9e93efa4e1138c9a7a5c594acd6c75a2fbf0c # v0.3
with:
version: v0.15.1
@@ -76,14 +76,14 @@ jobs:
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
uses: Noelware/docker-manifest-action@8e337e3cb9656abfcf20146b99706fd88716e942 # v0.4.0
with:
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
uses: Noelware/docker-manifest-action@8e337e3cb9656abfcf20146b99706fd88716e942 # v0.4.0
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 }}
@@ -94,21 +94,21 @@ jobs:
crane copy docker.io/falcosecurity/falco-no-driver:${{ inputs.tag }} docker.io/falcosecurity/falco:${{ inputs.tag }}-slim
- name: Create falco manifest on Docker Hub
uses: Noelware/docker-manifest-action@0.3.1
uses: Noelware/docker-manifest-action@8e337e3cb9656abfcf20146b99706fd88716e942 # v0.4.0
with:
inputs: docker.io/falcosecurity/falco:${{ inputs.tag }}
images: docker.io/falcosecurity/falco:aarch64-${{ inputs.tag }},docker.io/falcosecurity/falco:x86_64-${{ inputs.tag }}
push: true
- name: Create falco-driver-loader manifest on Docker Hub
uses: Noelware/docker-manifest-action@0.3.1
uses: Noelware/docker-manifest-action@8e337e3cb9656abfcf20146b99706fd88716e942 # v0.4.0
with:
inputs: docker.io/falcosecurity/falco-driver-loader:${{ inputs.tag }}
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
uses: Noelware/docker-manifest-action@8e337e3cb9656abfcf20146b99706fd88716e942 # v0.4.0
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 }}
@@ -116,6 +116,7 @@ jobs:
- name: Get Digests for images
id: digests
# We could probably use the docker-manifest-action output instead of recomputing those with crane
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
@@ -151,7 +152,7 @@ jobs:
- name: Setup Cosign
if: inputs.sign
uses: sigstore/cosign-installer@main
uses: sigstore/cosign-installer@11086d25041f77fe8fe7b9ea4e48e3b9192b8f19 # v3.1.2
with:
cosign-release: v2.0.2

View File

@@ -23,77 +23,64 @@ env:
jobs:
publish-packages:
runs-on: ubuntu-latest
container: docker.io/centos:7
container: docker.io/library/fedora:38
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- name: Install dependencies
run: |
yum install epel-release -y
yum update -y
yum install rpm-sign expect which createrepo gpg python python-pip -y
pip install awscli==1.19.47
dnf install rpm-sign expect which createrepo gpg python python-pip -y
pip install awscli==1.29.60
# Configure AWS role; see https://github.com/falcosecurity/test-infra/pull/1102
# Note: master CI can only push dev packages as we have 2 different roles for master and release.
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1
with:
role-to-assume: "arn:aws:iam::292999226676:role/github_actions-falco${{ inputs.bucket_suffix }}-s3"
aws-region: ${{ env.AWS_S3_REGION }}
- name: Download RPM x86_64
uses: actions/download-artifact@v3
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: falco-${{ inputs.version }}-x86_64.rpm
path: /tmp/falco-build-rpm
- name: Download RPM aarch64
uses: actions/download-artifact@v3
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: falco-${{ inputs.version }}-aarch64.rpm
path: /tmp/falco-build-rpm
- name: Download binary x86_64
uses: actions/download-artifact@v3
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: falco-${{ inputs.version }}-x86_64.tar.gz
path: /tmp/falco-build-bin
- name: Download binary aarch64
uses: actions/download-artifact@v3
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: falco-${{ inputs.version }}-aarch64.tar.gz
path: /tmp/falco-build-bin
- name: Download static binary x86_64
uses: actions/download-artifact@v3
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: falco-${{ inputs.version }}-static-x86_64.tar.gz
path: /tmp/falco-build-bin-static
- name: Import gpg key
- name: Import gpg key
env:
GPG_KEY: ${{ secrets.GPG_KEY }}
run: printenv GPG_KEY | gpg --import -
- name: Sign rpms
run: |
echo "%_signature gpg" > ~/.rpmmacros
echo "%_gpg_name Falcosecurity Package Signing" >> ~/.rpmmacros
echo "%__gpg_sign_cmd %{__gpg} --force-v3-sigs --batch --no-armor --passphrase-fd 3 --no-secmem-warning -u \"%{_gpg_name}\" -sb --digest-algo sha256 %{__plaintext_filename}'" >> ~/.rpmmacros
cat > ~/sign <<EOF
#!/usr/bin/expect -f
spawn rpmsign --addsign {*}\$argv
expect -exact "Enter pass phrase: "
send -- "\n"
expect eof
EOF
chmod +x ~/sign
~/sign /tmp/falco-build-rpm/falco-*.rpm
rpmsign --define '_gpg_name Falcosecurity Package Signing' --addsign /tmp/falco-build-rpm/falco-*.rpm
rpm --qf %{SIGPGP:pgpsig} -qp /tmp/falco-build-rpm/falco-*.rpm | grep SHA256
- name: Publish rpm
run: |
./scripts/publish-rpm -f /tmp/falco-build-rpm/falco-${{ inputs.version }}-x86_64.rpm -f /tmp/falco-build-rpm/falco-${{ inputs.version }}-aarch64.rpm -r rpm${{ inputs.bucket_suffix }}
@@ -112,7 +99,7 @@ jobs:
container: docker.io/debian:stable
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- name: Install dependencies
run: |
@@ -122,19 +109,19 @@ jobs:
# Configure AWS role; see https://github.com/falcosecurity/test-infra/pull/1102
# Note: master CI can only push dev packages as we have 2 different roles for master and release.
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1
with:
role-to-assume: "arn:aws:iam::292999226676:role/github_actions-falco${{ inputs.bucket_suffix }}-s3"
aws-region: ${{ env.AWS_S3_REGION }}
- name: Download deb x86_64
uses: actions/download-artifact@v3
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: falco-${{ inputs.version }}-x86_64.deb
path: /tmp/falco-build-deb
- name: Download deb aarch64
uses: actions/download-artifact@v3
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: falco-${{ inputs.version }}-aarch64.deb
path: /tmp/falco-build-deb

View File

@@ -19,21 +19,21 @@ on:
jobs:
test-packages:
# See https://github.com/actions/runner/issues/409#issuecomment-1158849936
runs-on: ${{ (inputs.arch == 'aarch64' && fromJSON('[ "self-hosted", "linux", "ARM64" ]')) || 'ubuntu-latest' }}
runs-on: ${{ (inputs.arch == 'aarch64' && 'actuated-arm64-8cpu-16gb') || 'ubuntu-22.04' }}
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
fetch-depth: 0
submodules: 'true'
- name: Setup Go
uses: actions/setup-go@v3
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
with:
go-version: '>=1.17.0'
- name: Download binary
uses: actions/download-artifact@v3
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: falco-${{ inputs.version }}${{ inputs.static && '-static' || '' }}-${{ inputs.arch }}.tar.gz
@@ -43,9 +43,17 @@ jobs:
tar -xvf $(ls falco-*.tar.gz)
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
# Note: most probably the plugin related tests should be moved to the plugin repo sooner or later.
- name: Install needed artifacts using falcoctl
if: ${{ inputs.static == false }}
run: |
sudo mkdir -p /usr/share/falco/plugins
sudo falcoctl artifact install k8saudit-rules
sudo falcoctl artifact install cloudtrail-rules
# We only run driver loader tests on x86_64
- name: Install dependencies for falco-driver-loader tests
if: ${{ inputs.arch == 'x86_64' }}
run: |
sudo apt update -y
@@ -63,8 +71,6 @@ 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
@@ -77,14 +83,14 @@ jobs:
./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
fi
cat ./report.txt | go-junit-report -set-exit-code > report.xml
popd
- name: Test Summary
if: always() # run this even if previous step fails
uses: test-summary/action@v2
uses: test-summary/action@62bc5c68de2a6a0d02039763b8c754569df99e3f # v2.1
with:
paths: "submodules/falcosecurity-testing/report.xml"
show: "fail"

79
.github/workflows/scorecard.yaml vendored Normal file
View File

@@ -0,0 +1,79 @@
# This workflow uses actions that are not certified by GitHub. They are provided
# by a third-party and are governed by separate terms of service, privacy
# policy, and support documentation.
name: Scorecard supply-chain security
on:
# To guarantee Maintained check is occasionally updated. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
schedule:
# Weekly on Mondays at 00:00.
- cron: '0 0 * * 1'
# The OSSF recommendation encourages to enable branch protection rules trigger
# to update the scorecard
# (https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection)
# but due to our GitHub org management this check is triggered too often and is
# therefore disabled.
# branch_protection_rule:
push:
branches: [ "master" ]
# Declare default permissions as read only.
permissions: read-all
jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
permissions:
# Needed to upload the results to code-scanning dashboard.
security-events: write
# Needed to publish results and get a badge (see publish_results below).
id-token: write
# Uncomment the permissions below if installing in a private repository.
# contents: read
# actions: read
steps:
- name: "Checkout code"
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@e38b1902ae4f44df626f11ba0734b14fb91f8f86 # v2.1.2
with:
results_file: results.sarif
results_format: sarif
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
# - you want to enable the Branch-Protection check on a *public* repository, or
# - you are installing Scorecard on a *private* repository
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
# Public repositories:
# - Publish results to OpenSSF REST API for easy access by consumers
# - Allows the repository to include the Scorecard badge.
# - See https://github.com/ossf/scorecard-action#publishing-results.
# For private repositories:
# - `publish_results` will always be set to `false`, regardless
# of the value entered here.
publish_results: true
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0
with:
name: SARIF file
path: results.sarif
retention-days: 5
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@17573ee1cc1b9d061760f3a006fc4aac4f944fd5 # v2.2.4
with:
sarif_file: results.sarif

View File

@@ -7,7 +7,7 @@ jobs:
steps:
- name: Checkout ⤵️
uses: actions/checkout@v3
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
@@ -25,7 +25,7 @@ jobs:
make -j4 cppcheck_htmlreport
- name: Upload reports ⬆️
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: static-analysis-reports
path: ./build/static-analysis-reports

1
.gitignore vendored
View File

@@ -5,3 +5,4 @@
.vscode/*
*.idea*
CMakeUserPresets.json

View File

@@ -72,6 +72,8 @@ This is a list of production adopters of Falco (in alphabetical order):
* [Thales Group](https://www.thalesgroup.com) Thales is a global technology leader with more than 81,000 employees on five continents. The Thales Group is investing in digital and “deep tech” innovations Big Data, artificial intelligence, connectivity, cybersecurity and quantum technology to build a future we can all trust. In the past few years, the Cloud-Native paradigms and its frameworks and tools have challenged the way applications and services are developed, delivered, and instantiated. All sorts of services are container-based workloads managed by higher level layers of orchestration such as the Kubernetes environment. Thales is committed to develop Cloud-Native services and to provide its customers with security features that ensure their applications and services are protected against cyber threats. Falco is a framework that can help Thales' products and services reach the level of trust, security and safety our clients need.
* [Thought Machine](https://www.thoughtmachine.net) Thought Machine builds Vault Core and Vault Payments: cloud-native core and payments technology enabling banks and fintechs to remain competitive and flourish into the future. Vault Core and Vault Payments are the foundation layer of a bank's technology stack. They can run any bank, any product, and any payment set. Thought Machine uses Falco to perform cloud agnostic real time detections of suspicious container behaviour.
* [Vinted](https://vinted.com/) Vinted uses Falco to continuously monitor container activities, identifying security threats, and ensuring compliance. The container-native approach, rule-based real-time threat detection, community support, extensibility, and compliance capabilities are the main factors why we chose it to enhance Vinted Kubernetes security. Falco Sidekick is used to send critical and warning severity alerts to our incident management solution (RTIR).
* [Xenit AB](https://xenit.se/contact/) Xenit is a growth company with services within cloud and digital transformation. We provide an open-source Kubernetes framework that we leverage to help our customers get their applications to production as quickly and as securely as possible. We use Falco's detection capabilities to identify anomalous behaviour within our clusters in both Azure and AWS.
@@ -86,6 +88,8 @@ This is a list of production adopters of Falco (in alphabetical order):
* [StackRox](https://stackrox.io) is the industrys first Kubernetes-native security platform enabling organizations to build, deploy, and run cloud-native applications securely. The platform works with Kubernetes environments and integrates with DevOps and security tools, enabling teams to operationalize and secure their supply chain, infrastructure, and workloads. StackRox aims to harness containerized applications development speed while giving operations and security teams greater context and risk profiling. StackRox leverages cloud-native principles and declarative artifacts to automate DevSecOps best practices.
* [Wireshark](https://www.wireshark.org) is the world's most powerful and popular network protocol analyzer. The Wireshark team is combining Wireshark's features and Falco libs to create Logray, a cloud and system log analyzer with advanced filtering, capture, and scripting capabilities.
## Adding a name
If you would like to add your name to this file, submit a pull request with your change.

View File

@@ -6,6 +6,7 @@ Released on 2023-10-27
NO CHANGES IN FALCO, ALL CHANGES IN LIBS.
## v0.36.1
Released on 2023-10-16
@@ -23,7 +24,7 @@ Released on 2023-10-16
## v0.36.0
Released on 2023-09-25
Released on 2023-09-26
### Breaking Changes

View File

@@ -21,7 +21,11 @@ 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)
if(WIN32)
set(CPACK_GENERATOR "NSIS") # this needs NSIS installed, and available
elseif (APPLE)
set(CPACK_GENERATOR "DragNDrop")
elseif(EMSCRIPTEN)
set(USE_BUNDLED_DEPS ON CACHE BOOL "" FORCE)
set(BUILD_DRIVER OFF CACHE BOOL "" FORCE)
set(ENABLE_DKMS OFF CACHE BOOL "" FORCE)
@@ -53,9 +57,6 @@ if (${EP_UPDATE_DISCONNECTED})
PROPERTY EP_UPDATE_DISCONNECTED TRUE)
endif()
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_EXTENSIONS OFF)
# Elapsed time
# set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CMAKE_COMMAND} -E time") # TODO(fntlnz, leodido): add a flag to enable this
@@ -83,56 +84,7 @@ else()
set(FALCO_TARGET_ARCH ${CMAKE_SYSTEM_PROCESSOR})
endif()
if(NOT FALCO_EXTRA_DEBUG_FLAGS)
set(FALCO_EXTRA_DEBUG_FLAGS "-D_DEBUG")
endif()
string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE)
if(CMAKE_BUILD_TYPE STREQUAL "debug")
set(KBUILD_FLAGS "${FALCO_EXTRA_DEBUG_FLAGS} ${FALCO_EXTRA_FEATURE_FLAGS}")
else()
set(CMAKE_BUILD_TYPE "release")
set(KBUILD_FLAGS "${FALCO_EXTRA_FEATURE_FLAGS}")
add_definitions(-DBUILD_TYPE_RELEASE)
endif()
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
if(MINIMAL_BUILD)
set(MINIMAL_BUILD_FLAGS "-DMINIMAL_BUILD")
endif()
if(MUSL_OPTIMIZED_BUILD)
set(MUSL_FLAGS "-static -Os -fPIE -pie")
add_definitions(-DMUSL_OPTIMIZED)
endif()
# explicitly set hardening flags
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
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()
set(CMAKE_COMMON_FLAGS "${FALCO_SECURITY_FLAGS} -Wall -ggdb ${FALCO_EXTRA_FEATURE_FLAGS} ${MINIMAL_BUILD_FLAGS} ${MUSL_FLAGS}")
if(BUILD_WARNINGS_AS_ERRORS)
set(CMAKE_SUPPRESSED_WARNINGS
"-Wno-unused-parameter -Wno-unused-variable -Wno-unused-but-set-variable -Wno-missing-field-initializers -Wno-sign-compare -Wno-type-limits -Wno-implicit-fallthrough -Wno-format-truncation -Wno-stringop-truncation -Wno-stringop-overflow -Wno-restrict"
)
set(CMAKE_COMMON_FLAGS "${CMAKE_COMMON_FLAGS} -Wextra -Werror ${CMAKE_SUPPRESSED_WARNINGS}")
endif()
set(CMAKE_C_FLAGS "${CMAKE_COMMON_FLAGS}")
set(CMAKE_CXX_FLAGS "-std=c++17 ${CMAKE_COMMON_FLAGS} -Wno-class-memaccess")
set(CMAKE_C_FLAGS_DEBUG "${FALCO_EXTRA_DEBUG_FLAGS}")
set(CMAKE_CXX_FLAGS_DEBUG "${FALCO_EXTRA_DEBUG_FLAGS}")
set(CMAKE_C_FLAGS_RELEASE "-O3 -fno-strict-aliasing -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -fno-strict-aliasing -DNDEBUG")
include(CompilerFlags)
set(PACKAGE_NAME "falco")
set(DRIVER_NAME "falco")
@@ -164,9 +116,6 @@ include(falcosecurity-libs)
# compute FALCO_VERSION (depends on libs)
include(falco-version)
# jq
include(jq)
# nlohmann-json
include(njson)
@@ -192,8 +141,8 @@ if (NOT EMSCRIPTEN)
include(tbb)
endif()
include(zlib)
if (NOT MINIMAL_BUILD)
include(zlib)
if (NOT WIN32 AND NOT APPLE AND NOT EMSCRIPTEN)
include(cares)
include(protobuf)
@@ -203,7 +152,16 @@ if (NOT MINIMAL_BUILD)
endif()
# Installation
install(FILES falco.yaml DESTINATION "${FALCO_ETC_DIR}" COMPONENT "${FALCO_COMPONENT_NAME}")
if(WIN32)
set(FALCO_INSTALL_CONF_FILE "%PROGRAMFILES%/${PACKAGE_NAME}-${FALCO_VERSION}/etc/falco/falco.yaml")
install(FILES falco.yaml DESTINATION etc/falco/ COMPONENT "${FALCO_COMPONENT_NAME}")
elseif(APPLE)
set(FALCO_INSTALL_CONF_FILE "/etc/falco/falco.yaml")
install(FILES falco.yaml DESTINATION etc/falco/ COMPONENT "${FALCO_COMPONENT_NAME}")
else()
set(FALCO_INSTALL_CONF_FILE "/etc/falco/falco.yaml")
install(FILES falco.yaml DESTINATION "${FALCO_ETC_DIR}" COMPONENT "${FALCO_COMPONENT_NAME}")
endif()
if(NOT MINIMAL_BUILD)
# Coverage
@@ -222,7 +180,6 @@ include(static-analysis)
# Shared build variables
set(FALCO_SINSP_LIBRARY sinsp)
set(FALCO_SHARE_DIR share/falco)
set(FALCO_PLUGINS_DIR ${FALCO_SHARE_DIR}/plugins)
set(FALCO_ABSOLUTE_SHARE_DIR "${CMAKE_INSTALL_PREFIX}/${FALCO_SHARE_DIR}")
set(FALCO_BIN_DIR bin)
@@ -231,7 +188,6 @@ add_subdirectory(userspace/engine)
add_subdirectory(userspace/falco)
if(NOT WIN32 AND NOT APPLE AND NOT EMSCRIPTEN AND NOT MUSL_OPTIMIZED_BUILD)
include(plugins)
include(falcoctl)
endif()

View File

@@ -2,7 +2,7 @@
[![Latest release](https://img.shields.io/github/v/release/falcosecurity/falco?style=for-the-badge)](https://github.com/falcosecurity/falco/releases/latest) [![Supported Architectures](https://img.shields.io/badge/ARCHS-x86__64%7Caarch64-blueviolet?style=for-the-badge)](https://github.com/falcosecurity/falco/releases/latest) [![License](https://img.shields.io/github/license/falcosecurity/falco?style=for-the-badge)](COPYING) [![Docs](https://img.shields.io/badge/docs-latest-green.svg?style=for-the-badge)](https://falco.org/docs)
[![Falco Core Repository](https://github.com/falcosecurity/evolution/blob/main/repos/badges/falco-core-blue.svg)](https://github.com/falcosecurity/evolution/blob/main/REPOSITORIES.md#core-scope) [![Stable](https://img.shields.io/badge/status-stable-brightgreen?style=for-the-badge)](https://github.com/falcosecurity/evolution/blob/main/REPOSITORIES.md#stable) [![OpenSSF Best Practices](https://img.shields.io/cii/summary/2317?label=OpenSSF%20Best%20Practices&style=for-the-badge)](https://bestpractices.coreinfrastructure.org/projects/2317)
[![Falco Core Repository](https://github.com/falcosecurity/evolution/blob/main/repos/badges/falco-core-blue.svg)](https://github.com/falcosecurity/evolution/blob/main/REPOSITORIES.md#core-scope) [![Stable](https://img.shields.io/badge/status-stable-brightgreen?style=for-the-badge)](https://github.com/falcosecurity/evolution/blob/main/REPOSITORIES.md#stable) [![OpenSSF Best Practices](https://img.shields.io/cii/summary/2317?label=OpenSSF%20Best%20Practices&style=for-the-badge)](https://bestpractices.coreinfrastructure.org/projects/2317) <a href="https://actuated.dev/"><img alt="Arm CI sponsored by Actuated" src="https://docs.actuated.dev/images/actuated-badge.png" width="120px"></img></a>
[![Falco](https://falco.org/img/brand/falco-horizontal-color.svg)](https://falco.org)

View File

@@ -30,6 +30,10 @@ else()
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_SYSTEM_PROCESSOR}")
endif()
if(WIN32)
SET(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
endif()
# Built packages will include only the following components
set(CPACK_INSTALL_CMAKE_PROJECTS
"${CMAKE_CURRENT_BINARY_DIR};${FALCO_COMPONENT_NAME};${FALCO_COMPONENT_NAME};/"
@@ -40,11 +44,6 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux") # only Linux has drivers
"${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)

View File

@@ -0,0 +1,101 @@
# SPDX-License-Identifier: Apache-2.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.
#
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_EXTENSIONS OFF)
if(NOT FALCO_EXTRA_DEBUG_FLAGS)
set(FALCO_EXTRA_DEBUG_FLAGS "-D_DEBUG")
endif()
string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE)
if(CMAKE_BUILD_TYPE STREQUAL "debug")
set(KBUILD_FLAGS "${FALCO_EXTRA_DEBUG_FLAGS} ${FALCO_EXTRA_FEATURE_FLAGS}")
else()
set(CMAKE_BUILD_TYPE "release")
set(KBUILD_FLAGS "${FALCO_EXTRA_FEATURE_FLAGS}")
add_definitions(-DBUILD_TYPE_RELEASE)
endif()
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
if(MINIMAL_BUILD)
set(MINIMAL_BUILD_FLAGS "-DMINIMAL_BUILD")
endif()
if(MUSL_OPTIMIZED_BUILD)
set(MUSL_FLAGS "-static -Os -fPIE -pie")
add_definitions(-DMUSL_OPTIMIZED)
endif()
# explicitly set hardening flags
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(FALCO_SECURITY_FLAGS "")
if(LINUX)
set(FALCO_SECURITY_FLAGS "${FALCO_SECURITY_FLAGS} -Wl,-z,relro,-z,now -fstack-protector-strong")
endif()
if(NOT MSVC)
if(CMAKE_BUILD_TYPE STREQUAL "release")
set(FALCO_SECURITY_FLAGS "${FALCO_SECURITY_FLAGS} -D_FORTIFY_SOURCE=2")
endif()
set(CMAKE_COMMON_FLAGS "${FALCO_SECURITY_FLAGS} -Wall -ggdb ${FALCO_EXTRA_FEATURE_FLAGS} ${MINIMAL_BUILD_FLAGS} ${MUSL_FLAGS}")
if(BUILD_WARNINGS_AS_ERRORS)
set(CMAKE_SUPPRESSED_WARNINGS
"-Wno-unused-parameter -Wno-unused-variable -Wno-unused-but-set-variable -Wno-missing-field-initializers -Wno-sign-compare -Wno-type-limits -Wno-implicit-fallthrough -Wno-format-truncation -Wno-stringop-truncation -Wno-stringop-overflow -Wno-restrict"
)
set(CMAKE_COMMON_FLAGS "${CMAKE_COMMON_FLAGS} -Wextra -Werror ${CMAKE_SUPPRESSED_WARNINGS}")
endif()
set(CMAKE_C_FLAGS "${CMAKE_COMMON_FLAGS}")
set(CMAKE_CXX_FLAGS "-std=c++17 ${CMAKE_COMMON_FLAGS} -Wno-class-memaccess")
set(CMAKE_C_FLAGS_DEBUG "${FALCO_EXTRA_DEBUG_FLAGS}")
set(CMAKE_CXX_FLAGS_DEBUG "${FALCO_EXTRA_DEBUG_FLAGS}")
set(CMAKE_C_FLAGS_RELEASE "-O3 -fno-strict-aliasing -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -fno-strict-aliasing -DNDEBUG")
else() # MSVC
set(MINIMAL_BUILD ON)
# The WIN32_LEAN_AND_MEAN define avoids possible macro pollution
# when a libsinsp consumer includes the windows.h header.
# See: https://stackoverflow.com/a/28380820
add_compile_definitions(
_HAS_STD_BYTE=0
_CRT_SECURE_NO_WARNINGS
WIN32
MINIMAL_BUILD
WIN32_LEAN_AND_MEAN
)
set(FALCOSECURITY_LIBS_COMMON_FLAGS "/EHsc /W3 /Zi /std:c++17")
set(FALCOSECURITY_LIBS_DEBUG_FLAGS "/MTd /Od")
set(FALCOSECURITY_LIBS_RELEASE_FLAGS "/MT")
set(CMAKE_C_FLAGS "${FALCOSECURITY_LIBS_COMMON_FLAGS}")
set(CMAKE_CXX_FLAGS "${FALCOSECURITY_LIBS_COMMON_FLAGS}")
set(CMAKE_C_FLAGS_DEBUG "${FALCOSECURITY_LIBS_DEBUG_FLAGS}")
set(CMAKE_CXX_FLAGS_DEBUG "${FALCOSECURITY_LIBS_DEBUG_FLAGS}")
set(CMAKE_C_FLAGS_RELEASE "${FALCOSECURITY_LIBS_RELEASE_FLAGS}")
set(CMAKE_CXX_FLAGS_RELEASE "${FALCOSECURITY_LIBS_RELEASE_FLAGS}")
endif()

View File

@@ -34,8 +34,8 @@ else()
# In case you want to test against another driver version (or branch, or commit) just pass the variable -
# ie., `cmake -DDRIVER_VERSION=dev ..`
if(NOT DRIVER_VERSION)
set(DRIVER_VERSION "6.0.1+driver")
set(DRIVER_CHECKSUM "SHA256=2b4412b5053c8ed5bd1a9de745faa16ec0210dc65dc858af65951d4c8d22207c")
set(DRIVER_VERSION "7.0.0+driver")
set(DRIVER_CHECKSUM "SHA256=9f2a0f14827c0d9d1c3d1abe45b8f074dea531ebeca9859363a92f0d2475757e")
endif()
# cd /path/to/build && cmake /path/to/source

View File

@@ -16,14 +16,14 @@ include(ExternalProject)
string(TOLOWER ${CMAKE_HOST_SYSTEM_NAME} FALCOCTL_SYSTEM_NAME)
set(FALCOCTL_VERSION "0.6.2")
set(FALCOCTL_VERSION "0.7.1")
if(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64")
set(FALCOCTL_SYSTEM_PROC_GO "amd64")
set(FALCOCTL_HASH "2d06d7577dbae91fb085f71477ff6e22076a815978bddd036984fa077236a515")
set(FALCOCTL_HASH "f142507c0e2b1e7dc03fd0b1ec36b479eb171f1f58c17f90d2d8edeb00668ef5")
else() # aarch64
set(FALCOCTL_SYSTEM_PROC_GO "arm64")
set(FALCOCTL_HASH "0b711a1b3499f479d999f4f4d2c94fc4f0bc23a2506711b613e6eedb0593631b")
set(FALCOCTL_HASH "93e4800b68e21057da82c8c7aafa0970598594d62cd9929ebb9b38a9c02159a6")
endif()
ExternalProject_Add(

View File

@@ -26,17 +26,17 @@ if(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 ..`
# 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 ..`
# ie., `cmake -DFALCOSECURITY_LIBS_VERSION=dev ..`
if(NOT FALCOSECURITY_LIBS_VERSION)
set(FALCOSECURITY_LIBS_VERSION "0.13.4")
set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=6b4a5c56422588b6ccaa53c976a9fbbcdb8d7918720c1b46207afe7ca46e8c29")
set(FALCOSECURITY_LIBS_VERSION "0.14.1")
set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=defdea24bf3b176c63f10900d3716fe4373151965cc09d3fe67a31a3a9af0b13")
endif()
# cd /path/to/build && cmake /path/to/source
@@ -84,10 +84,11 @@ set(CREATE_TEST_TARGETS OFF CACHE BOOL "")
set(BUILD_LIBSCAP_EXAMPLES OFF CACHE BOOL "")
set(USE_BUNDLED_TBB ON CACHE BOOL "")
set(USE_BUNDLED_B64 ON CACHE BOOL "")
set(USE_BUNDLED_JSONCPP ON CACHE BOOL "")
set(USE_BUNDLED_NLOHMANN_JSON ON CACHE BOOL "")
set(USE_BUNDLED_VALIJSON ON CACHE BOOL "")
set(USE_BUNDLED_RE2 ON CACHE BOOL "")
set(USE_BUNDLED_UTHASH ON CACHE BOOL "")
list(APPEND CMAKE_MODULE_PATH "${FALCOSECURITY_LIBS_SOURCE_DIR}/cmake/modules")
@@ -95,12 +96,15 @@ include(CheckSymbolExists)
check_symbol_exists(strlcpy "string.h" HAVE_STRLCPY)
if(HAVE_STRLCPY)
message(STATUS "Existing strlcpy found, will *not* use local definition by setting -DHAVE_STRLCPY.")
message(STATUS "Existing strlcpy and strlcat found, will *not* use local definition by setting -DHAVE_STRLCPY and -DHAVE_STRLCAT.")
add_definitions(-DHAVE_STRLCPY)
add_definitions(-DHAVE_STRLCAT)
else()
message(STATUS "No strlcpy found, will use local definition")
message(STATUS "No strlcpy and strlcat found, will use local definition")
endif()
include(driver)
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
include(driver)
endif()
include(libscap)
include(libsinsp)

View File

@@ -1,28 +0,0 @@
# SPDX-License-Identifier: Apache-2.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.
#
set(LIBYAML_SRC "${PROJECT_BINARY_DIR}/libyaml-prefix/src/libyaml")
set(LIBYAML_INSTALL_DIR "${LIBYAML_SRC}/target")
message(STATUS "Using bundled libyaml in '${LIBYAML_SRC}'")
set(LIBYAML_LIB "${LIBYAML_SRC}/src/.libs/libyaml.a")
externalproject_add(
libyaml
URL "https://github.com/yaml/libyaml/releases/download/0.2.5/yaml-0.2.5.tar.gz"
URL_HASH "SHA256=c642ae9b75fee120b2d96c712538bd2cf283228d2337df2cf2988e3c02678ef4"
CONFIGURE_COMMAND ./configure --prefix=${LIBYAML_INSTALL_DIR} CFLAGS=-fPIC CPPFLAGS=-fPIC --enable-static=true --enable-shared=false
BUILD_COMMAND ${CMD_MAKE}
BUILD_IN_SOURCE 1
BUILD_BYPRODUCTS ${LIBYAML_LIB}
INSTALL_COMMAND ${CMD_MAKE} install
)

View File

@@ -12,24 +12,16 @@
# specific language governing permissions and limitations under the License.
#
#
# nlohmann-json
#
if(NJSON_INCLUDE)
# Adding the custom target we can use it with `add_dependencies()`
if(NOT TARGET njson)
add_custom_target(njson)
endif()
else()
# We always use the bundled version
set(NJSON_SRC "${PROJECT_BINARY_DIR}/njson-prefix/src/njson")
set(NJSON_INCLUDE "${NJSON_SRC}/single_include")
ExternalProject_Add(
njson
if(USE_BUNDLED_NLOHMANN_JSON)
ExternalProject_Add(njson
URL "https://github.com/nlohmann/json/archive/v3.3.0.tar.gz"
URL_HASH "SHA256=2fd1d207b4669a7843296c41d3b6ac5b23d00dec48dba507ba051d14564aa801"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND "")
message(STATUS "Using bundled nlohmann-json in '${NJSON_SRC}'")
CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=${PROJECT_BINARY_DIR}/njson-prefix -DJSON_BuildTests=OFF -DBUILD_TESTING=OFF
)
set(nlohmann_json_INCLUDE_DIRS ${PROJECT_BINARY_DIR}/njson-prefix/include)
else()
find_package(nlohmann_json CONFIG REQUIRED)
get_target_property(nlohmann_json_INCLUDE_DIRS nlohmann_json::nlohmann_json INTERFACE_INCLUDE_DIRECTORIES)
add_custom_target(njson)
endif()

View File

@@ -1,98 +0,0 @@
# SPDX-License-Identifier: Apache-2.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(ExternalProject)
# 'stable' or 'dev'
set(PLUGINS_DOWNLOAD_BUCKET "stable")
string(TOLOWER ${CMAKE_HOST_SYSTEM_NAME} PLUGINS_SYSTEM_NAME)
if(NOT DEFINED PLUGINS_COMPONENT_NAME)
set(PLUGINS_COMPONENT_NAME "${CMAKE_PROJECT_NAME}-plugins")
endif()
# k8saudit
set(PLUGIN_K8S_AUDIT_VERSION "0.6.1")
if(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64")
set(PLUGIN_K8S_AUDIT_HASH "e2908ebf2c03feecd26307ceab55aec9cae1cbc63d6aa05e147d8786e7670fb0")
else() # aarch64
set(PLUGIN_K8S_AUDIT_HASH "8987a995fa09518aebc488ba549448166d605596c2d6478c10415a9d9f5f05dd")
endif()
ExternalProject_Add(
k8saudit-plugin
URL "https://download.falco.org/plugins/${PLUGINS_DOWNLOAD_BUCKET}/k8saudit-${PLUGIN_K8S_AUDIT_VERSION}-${PLUGINS_SYSTEM_NAME}-${CMAKE_HOST_SYSTEM_PROCESSOR}.tar.gz"
URL_HASH "SHA256=${PLUGIN_K8S_AUDIT_HASH}"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND "")
install(FILES "${PROJECT_BINARY_DIR}/k8saudit-plugin-prefix/src/k8saudit-plugin/libk8saudit.so" DESTINATION "${FALCO_PLUGINS_DIR}" COMPONENT "${PLUGINS_COMPONENT_NAME}")
ExternalProject_Add(
k8saudit-rules
URL "https://download.falco.org/plugins/${PLUGINS_DOWNLOAD_BUCKET}/k8saudit-rules-${PLUGIN_K8S_AUDIT_VERSION}.tar.gz"
URL_HASH "SHA256=36321b3f1d7969926073a4d40bbbb7b4b28805b038c067f140795210ab641161"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND "")
install(FILES "${PROJECT_BINARY_DIR}/k8saudit-rules-prefix/src/k8saudit-rules/k8s_audit_rules.yaml" DESTINATION "${FALCO_ETC_DIR}" COMPONENT "${PLUGINS_COMPONENT_NAME}")
# cloudtrail
set(PLUGIN_CLOUDTRAIL_VERSION "0.9.0")
if(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64")
set(PLUGIN_CLOUDTRAIL_HASH "c8dc8ea5337aa9475042e6441320a5188bbf76977e3a69dd34a49a6251f8e9ad")
else() # aarch64
set(PLUGIN_CLOUDTRAIL_HASH "bea12e81409c3df5698f7ab6a740ee9698b9dd1275b5985810daf70ac505c810")
endif()
ExternalProject_Add(
cloudtrail-plugin
URL "https://download.falco.org/plugins/${PLUGINS_DOWNLOAD_BUCKET}/cloudtrail-${PLUGIN_CLOUDTRAIL_VERSION}-${PLUGINS_SYSTEM_NAME}-${CMAKE_HOST_SYSTEM_PROCESSOR}.tar.gz"
URL_HASH "SHA256=${PLUGIN_CLOUDTRAIL_HASH}"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND "")
install(FILES "${PROJECT_BINARY_DIR}/cloudtrail-plugin-prefix/src/cloudtrail-plugin/libcloudtrail.so" DESTINATION "${FALCO_PLUGINS_DIR}" COMPONENT "${PLUGINS_COMPONENT_NAME}")
ExternalProject_Add(
cloudtrail-rules
URL "https://download.falco.org/plugins/${PLUGINS_DOWNLOAD_BUCKET}/cloudtrail-rules-${PLUGIN_CLOUDTRAIL_VERSION}.tar.gz"
URL_HASH "SHA256=b0c2b6c78d61cc3e7fb66445bcd8f763d15eb4a24f518385377e704aacec6b3f"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND "")
install(FILES "${PROJECT_BINARY_DIR}/cloudtrail-rules-prefix/src/cloudtrail-rules/aws_cloudtrail_rules.yaml" DESTINATION "${FALCO_ETC_DIR}" COMPONENT "${PLUGINS_COMPONENT_NAME}")
# json
set(PLUGIN_JSON_VERSION "0.7.1")
if(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64")
set(PLUGIN_JSON_HASH "3177fd667b384df2ffd2ae3260bda867c407c09d3fbcae841af204b82c1341c1")
else() # aarch64
set(PLUGIN_JSON_HASH "3b5d0a9190bfd08e21915f997f88ca314f2027564a022eb88eef80ff4e2c77fa")
endif()
ExternalProject_Add(
json-plugin
URL "https://download.falco.org/plugins/${PLUGINS_DOWNLOAD_BUCKET}/json-${PLUGIN_JSON_VERSION}-${PLUGINS_SYSTEM_NAME}-${CMAKE_HOST_SYSTEM_PROCESSOR}.tar.gz"
URL_HASH "SHA256=${PLUGIN_JSON_HASH}"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND "")
install(FILES "${PROJECT_BINARY_DIR}/json-plugin-prefix/src/json-plugin/libjson.so" DESTINATION "${FALCO_PLUGINS_DIR}" COMPONENT "${PLUGINS_COMPONENT_NAME}")

View File

@@ -16,8 +16,8 @@ include(GNUInstallDirs)
include(ExternalProject)
# falco_rules.yaml
set(FALCOSECURITY_RULES_FALCO_VERSION "falco-rules-2.0.0")
set(FALCOSECURITY_RULES_FALCO_CHECKSUM "SHA256=48b6c5ae7a619a320eb51dbe036d1bc78622ab692956c9493390678874757b32")
set(FALCOSECURITY_RULES_FALCO_VERSION "falco-rules-3.0.0-rc1")
set(FALCOSECURITY_RULES_FALCO_CHECKSUM "SHA256=2e91799fee49c2daf58fb482e47410a21433eb116e02cde18206f7af87449ddb")
set(FALCOSECURITY_RULES_FALCO_PATH "${PROJECT_BINARY_DIR}/falcosecurity-rules-falco-prefix/src/falcosecurity-rules-falco/falco_rules.yaml")
ExternalProject_Add(
falcosecurity-rules-falco
@@ -34,7 +34,11 @@ set(FALCOSECURITY_RULES_LOCAL_PATH "${PROJECT_BINARY_DIR}/falcosecurity-rules-lo
file(WRITE "${FALCOSECURITY_RULES_LOCAL_PATH}" "# Your custom rules!\n")
if(NOT DEFINED FALCO_ETC_DIR)
set(FALCO_ETC_DIR "${CMAKE_INSTALL_FULL_SYSCONFDIR}/falco")
set(FALCO_ETC_DIR "${CMAKE_INSTALL_FULL_SYSCONFDIR}/falco")
endif()
if(WIN32 OR APPLE)
set(FALCO_ETC_DIR "etc/falco")
endif()
if(NOT DEFINED FALCO_RULES_DEST_FILENAME)

View File

@@ -24,13 +24,18 @@ if(NOT USE_BUNDLED_DEPS)
else()
set(YAMLCPP_SRC "${PROJECT_BINARY_DIR}/yamlcpp-prefix/src/yamlcpp")
message(STATUS "Using bundled yaml-cpp in '${YAMLCPP_SRC}'")
set(YAMLCPP_LIB "${YAMLCPP_SRC}/libyaml-cpp.a")
if(NOT WIN32)
set(YAMLCPP_LIB "${YAMLCPP_SRC}/libyaml-cpp.a")
else()
set(YAMLCPP_LIB "${YAMLCPP_SRC}/${CMAKE_BUILD_TYPE}/yaml-cpp.lib")
endif()
set(YAMLCPP_INCLUDE_DIR "${YAMLCPP_SRC}/include")
ExternalProject_Add(
yamlcpp
URL "https://github.com/jbeder/yaml-cpp/archive/yaml-cpp-0.6.2.tar.gz"
URL_HASH "SHA256=e4d8560e163c3d875fd5d9e5542b5fd5bec810febdcba61481fe5fc4e6b1fd05"
URL "https://github.com/jbeder/yaml-cpp/archive/yaml-cpp-0.7.0.tar.gz"
URL_HASH "SHA256=43e6a9fcb146ad871515f0d0873947e5d497a1c9c60c58cb102a97b47208b7c3"
BUILD_BYPRODUCTS ${YAMLCPP_LIB}
CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release -DYAML_MSVC_SHARED_RT=Off -DYAML_BUILD_SHARED_LIBS=Off -DYAML_CPP_BUILD_TESTS=Off -DYAML_CPP_BUILD_TOOLS=OFF -DYAML_CPP_BUILD_CONTRIB=OFF -DCMAKE_DEBUG_POSTFIX=''
BUILD_IN_SOURCE 1
INSTALL_COMMAND "")
endif()

View File

@@ -18,6 +18,28 @@
#
print_usage() {
echo ""
echo "Usage:"
echo " docker run -i -t --privileged -v /root/.falco:/root/.falco -v /proc:/host/proc:ro -v /boot:/host/boot:ro -v /lib/modules:/host/lib/modules:ro -v /usr:/host/usr:ro -v /etc:/host/etc:ro falcosecurity/falco-driver-loader-legacy:latest [driver] [options]"
echo ""
echo "Available drivers:"
echo " kmod kernel module (default)"
echo " ebpf eBPF probe"
echo ""
echo "Options:"
echo " --help show this help message"
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 " --print-env skip execution and print env variables for other tools to consume"
echo ""
echo "Environment variables:"
echo " FALCOCTL_DRIVER_REPOS specify different URL(s) where to look for prebuilt Falco drivers (comma separated)"
echo " FALCOCTL_DRIVER_NAME specify a different name for the driver"
echo ""
}
echo "* Setting up /usr/src links from host"
for i in "$HOST_ROOT/usr/src"/*
@@ -26,4 +48,64 @@ do
ln -s "$i" "/usr/src/$base"
done
/usr/bin/falco-driver-loader "$@"
ENABLE_COMPILE="false"
ENABLE_DOWNLOAD="false"
has_driver=
has_opts=
while test $# -gt 0; do
case "$1" in
kmod|ebpf)
if [ -n "$has_driver" ]; then
>&2 echo "Only one driver per invocation"
print_usage
exit 1
else
/usr/bin/falcoctl driver config --type $1
has_driver="true"
fi
;;
-h|--help)
print_usage
exit 0
;;
--clean)
/usr/bin/falcoctl driver cleanup
exit 0
;;
--compile)
ENABLE_COMPILE="true"
has_opts="true"
;;
--download)
ENABLE_DOWNLOAD="true"
has_opts="true"
;;
--source-only)
>&2 echo "Support dropped in Falco 0.37.0."
print_usage
exit 1
;;
--print-env)
/usr/bin/falcoctl driver printenv
exit 0
;;
--*)
>&2 echo "Unknown option: $1"
print_usage
exit 1
;;
*)
>&2 echo "Unknown driver: $1"
print_usage
exit 1
;;
esac
shift
done
if [ -z "$has_opts" ]; then
ENABLE_COMPILE="true"
ENABLE_DOWNLOAD="true"
fi
/usr/bin/falcoctl driver install --compile=$ENABLE_COMPILE --download=$ENABLE_DOWNLOAD

View File

@@ -18,6 +18,28 @@
#
print_usage() {
echo ""
echo "Usage:"
echo " docker run -i -t --privileged -v /root/.falco:/root/.falco -v /proc:/host/proc:ro -v /boot:/host/boot:ro -v /lib/modules:/host/lib/modules:ro -v /usr:/host/usr:ro -v /etc:/host/etc:ro falcosecurity/falco-driver-loader:latest [driver] [options]"
echo ""
echo "Available drivers:"
echo " kmod kernel module (default)"
echo " ebpf eBPF probe"
echo ""
echo "Options:"
echo " --help show this help message"
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 " --print-env skip execution and print env variables for other tools to consume"
echo ""
echo "Environment variables:"
echo " FALCOCTL_DRIVER_REPOS specify different URL(s) where to look for prebuilt Falco drivers (comma separated)"
echo " FALCOCTL_DRIVER_NAME specify a different name for the driver"
echo ""
}
echo "* Setting up /usr/src links from host"
for i in "$HOST_ROOT/usr/src"/*
@@ -26,4 +48,64 @@ do
ln -s "$i" "/usr/src/$base"
done
/usr/bin/falco-driver-loader "$@"
ENABLE_COMPILE="false"
ENABLE_DOWNLOAD="false"
has_driver=
has_opts=
while test $# -gt 0; do
case "$1" in
kmod|ebpf)
if [ -n "$has_driver" ]; then
>&2 echo "Only one driver per invocation"
print_usage
exit 1
else
/usr/bin/falcoctl driver config --type $1
has_driver="true"
fi
;;
-h|--help)
print_usage
exit 0
;;
--clean)
/usr/bin/falcoctl driver cleanup
exit 0
;;
--compile)
ENABLE_COMPILE="true"
has_opts="true"
;;
--download)
ENABLE_DOWNLOAD="true"
has_opts="true"
;;
--source-only)
>&2 echo "Support dropped in Falco 0.37.0."
print_usage
exit 1
;;
--print-env)
/usr/bin/falcoctl driver printenv
exit 0
;;
--*)
>&2 echo "Unknown option: $1"
print_usage
exit 1
;;
*)
>&2 echo "Unknown driver: $1"
print_usage
exit 1
;;
esac
shift
done
if [ -z "$has_opts" ]; then
ENABLE_COMPILE="true"
ENABLE_DOWNLOAD="true"
fi
/usr/bin/falcoctl driver install --compile=$ENABLE_COMPILE --download=$ENABLE_DOWNLOAD

View File

@@ -19,17 +19,26 @@ RUN cp /etc/skel/.bashrc /root && cp /etc/skel/.profile /root
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
bc \
bison \
ca-certificates \
clang \
curl \
dkms \
dwarves \
flex \
gcc \
gcc-11 \
gnupg2 \
jq \
libelf1 \
libc6-dev \
libelf-dev \
libssl-dev \
llvm \
make \
netcat-openbsd \
patchelf \
xz-utils \
&& rm -rf /var/lib/apt/lists/*
RUN curl -s https://falco.org/repo/falcosecurity-packages.asc | apt-key add - \

View File

@@ -17,6 +17,29 @@
# limitations under the License.
#
print_usage() {
echo ""
echo "Usage:"
echo " docker run -i -t --privileged -v /root/.falco:/root/.falco -v /proc:/host/proc:ro -v /boot:/host/boot:ro -v /lib/modules:/host/lib/modules:ro -v /usr:/host/usr:ro -v /etc:/host/etc:ro -e 'FALCO_DRIVER_LOADER_OPTIONS=[driver] [options]' falcosecurity/falco:latest"
echo ""
echo "Available FALCO_DRIVER_LOADER_OPTIONS drivers:"
echo " kmod kernel module (default)"
echo " ebpf eBPF probe"
echo ""
echo "FALCO_DRIVER_LOADER_OPTIONS options:"
echo " --help show this help message"
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 " --print-env skip execution and print env variables for other tools to consume"
echo ""
echo "Environment variables:"
echo " FALCOCTL_DRIVER_REPOS specify different URL(s) where to look for prebuilt Falco drivers (comma separated)"
echo " FALCOCTL_DRIVER_NAME specify a different name for the driver"
echo ""
}
# Set the SKIP_DRIVER_LOADER variable to skip loading the driver
if [[ -z "${SKIP_DRIVER_LOADER}" ]]; then
@@ -29,9 +52,69 @@ if [[ -z "${SKIP_DRIVER_LOADER}" ]]; then
done
# 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
# shell expansion and use it as argument list for falcoctl
read -a falco_driver_loader_option_arr <<< $FALCO_DRIVER_LOADER_OPTIONS
/usr/bin/falco-driver-loader "${falco_driver_loader_option_arr[@]}"
ENABLE_COMPILE="false"
ENABLE_DOWNLOAD="false"
has_driver=
has_opts=
for opt in "${falco_driver_loader_option_arr[@]}"
do
case "$opt" in
kmod|ebpf)
if [ -n "$has_driver" ]; then
>&2 echo "Only one driver per invocation"
print_usage
exit 1
else
/usr/bin/falcoctl driver config --type $opt
has_driver="true"
fi
;;
-h|--help)
print_usage
exit 0
;;
--clean)
/usr/bin/falcoctl driver cleanup
exit 0
;;
--compile)
ENABLE_COMPILE="true"
has_opts="true"
;;
--download)
ENABLE_DOWNLOAD="true"
has_opts="true"
;;
--source-only)
>&2 echo "Support dropped in Falco 0.37.0."
print_usage
exit 1
;;
--print-env)
/usr/bin/falcoctl driver printenv
exit 0
;;
--*)
>&2 echo "Unknown option: $1"
print_usage
exit 1
;;
*)
>&2 echo "Unknown driver: $1"
print_usage
exit 1
;;
esac
done
if [ -z "$has_opts" ]; then
ENABLE_COMPILE="true"
ENABLE_DOWNLOAD="true"
fi
/usr/bin/falcoctl driver install --compile=$ENABLE_COMPILE --download=$ENABLE_DOWNLOAD
fi
exec "$@"

View File

@@ -15,7 +15,7 @@ RUN curl -L -o falco.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
rm -rf /falco/usr/src/falco-*
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

View File

@@ -16,7 +16,7 @@ RUN FALCO_VERSION_URLENCODED=$(echo -n ${FALCO_VERSION}|jq -sRr @uri) && \
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
rm -rf /falco/usr/src/falco-*
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

View File

@@ -27,6 +27,8 @@
# (Falco environment variables)
# Falco rules files
# rules_file
# Falco engine
# engine
# Falco plugins
# load_plugins
# plugins
@@ -39,7 +41,6 @@
# json_include_output_property
# json_include_tags_property
# buffered_outputs
# outputs (throttling)
# rule_matching
# outputs_queue
# Falco outputs channels
@@ -60,16 +61,13 @@
# Falco logging / alerting / metrics related to software functioning (advanced)
# output_timeout
# syscall_event_timeouts
# syscall_event_drops
# syscall_event_drops -> [CHANGE NOTICE] Automatic notifications will be simplified in Falco 0.38! If you depend on the detailed drop counters payload, use 'metrics.output_rule' along with 'metrics.kernel_event_counters_enabled' instead
# metrics
# Falco performance tuning (advanced)
# syscall_buf_size_preset
# syscall_drop_failed_exit
# syscall_buf_size_preset [DEPRECATED] -> Replaced by `engine.<driver>.buf_size_preset` starting Falco 0.38!
# syscall_drop_failed_exit [DEPRECATED] -> Replaced by `engine.<driver>.drop_failed_exit` starting Falco 0.38!
# base_syscalls
# modern_bpf.cpus_for_each_syscall_buffer
# Falco cloud orchestration systems integration
# metadata_download
# (Guidance for Kubernetes container engine command-line args settings)
# modern_bpf.cpus_for_each_syscall_buffer [DEPRECATED] -> Replaced by `engine.modern_ebpf.cpus_for_each_buffer` starting Falco 0.38!
################################
@@ -81,9 +79,9 @@
# configuration options from this config file as command-line arguments by using
# the `-o` flag followed by the option name and value. In the following example,
# three config options (`json_output`, `log_level`, and
# `modern_bpf.cpus_for_each_syscall_buffer`) are passed as command-line
# `engine.kind`) are passed as command-line
# arguments with their corresponding values: falco -o "json_output=true"
# -o "log_level=debug" -o "modern_bpf.cpus_for_each_syscall_buffer=4"
# -o "log_level=debug" -o "engine.kind=kmod"
# Please note that command-line arguments take precedence over the options
# specified in this config file.
@@ -94,16 +92,32 @@
# Customize Falco settings using environment variables:
#
# - "HOST_ROOT": Specifies the prefix to the underlying host `/proc` filesystem
# - HOST_ROOT: Specifies the prefix to the underlying host `/proc` filesystem
# when deploying Falco over a container with read-only host mounts instead of
# directly on the host. Defaults to "/host".
# - "FALCO_BPF_PROBE": Specify a custom path to the BPF object code file (`bpf`
#
# - !!! [DEPRECATED] FALCO_BPF_PROBE: Specify a custom path to the BPF object code file (`bpf`
# driver). This is not needed for the modern_bpf driver.
# - "FALCO_HOSTNAME": Customize the hostname output field logged by Falco by
# -> Replaced by `engine.kind: ebpf` and `engine.ebpf` starting Falco 0.38!
#
# - FALCO_HOSTNAME: Customize the hostname output field logged by Falco by
# setting the "FALCO_HOSTNAME" environment variable.
# - "FALCO_CGROUP_MEM_PATH": Specifies the file path holding the container
#
# - FALCO_CGROUP_MEM_PATH: Specifies the file path holding the container
# memory usage metric for the `metrics` feature. Defaults to
# "/sys/fs/cgroup/memory/memory.usage_in_bytes" (Kubernetes).
#
# - SKIP_DRIVER_LOADER is used by the Falco fat image to skip the driver loading part.
#
# - FALCO_FRONTEND is useful when set to noninteractive to skip the dialog choice during
# the installation of Falco deb/rpm packages. This setting is somewhat similar to DEBIAN_FRONTEND.
#
# - FALCO_DRIVER_CHOICE is useful when set to kmod, ebpf, or modern_ebpf (matching the names
# used in engine.kind in the Falco config) during the installation of Falco deb/rpm packages.
# It skips the dialog choice but retains the driver configuration.
#
# - FALCOCTL_ENABLED is useful when set to 'no' during the installation of Falco deb/rpm packages,
# disabling the automatic artifacts followed by falcoctl.
#####################
@@ -148,6 +162,197 @@ rules_file:
- /etc/falco/falco_rules.local.yaml
- /etc/falco/rules.d
################
# Falco engine #
################
# [Stable] `engine`
#
# --- [Description]
#
# Falco supports different engines to generate events.
# Choose the appropriate engine kind based on your system's configuration and requirements.
#
# Available engines:
# - `kmod`: Kernel Module (Kernel Module)
# - `ebpf`: eBPF (eBPF probe)
# - `modern_ebpf`: Modern eBPF (CO-RE eBPF probe)
# - `gvisor`: gVisor (gVisor sandbox)
# - `replay`: Replay a scap trace file
# - `nodriver`: No driver is injected into the system.
# This is useful to debug and to run plugins with 'syscall' source.
#
# Only one engine can be specified in the `kind` key.
# Moreover, for each engine multiple options might be available,
# grouped under engine-specific configuration keys.
# Some of them deserve an in-depth description:
#
################### `buf_size_preset`
#
# --- [Description]
#
# The syscall buffer index determines the size of the shared space between Falco
# and its drivers. This shared space serves as a temporary storage for syscall
# events, allowing them to be transferred from the kernel to the userspace
# efficiently. The buffer size for each online CPU is determined by the buffer
# index, and each CPU has its own dedicated buffer. Adjusting this index allows
# you to control the overall size of the syscall buffers.
#
# --- [Usage]
#
# The index 0 is reserved, and each subsequent index corresponds to an
# increasing size in bytes. For example, index 1 corresponds to a size of 1 MB,
# index 2 corresponds to 2 MB, and so on:
#
# [(*), 1 MB, 2 MB, 4 MB, 8 MB, 16 MB, 32 MB, 64 MB, 128 MB, 256 MB, 512 MB]
# ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
# | | | | | | | | | | |
# 0 1 2 3 4 5 6 7 8 9 10
#
#
# The buffer dimensions in bytes are determined by the following requirements:
# (1) a power of 2.
# (2) a multiple of your system_page_dimension.
# (3) greater than `2 * (system_page_dimension).
#
# The buffer size constraints may limit the usability of certain indexes. Let's
# consider an example to illustrate this:
#
# If your system has a page size of 1 MB, the first available buffer size would
# be 4 MB because 2 MB is exactly equal to 2 * (system_page_size), which is not
# sufficient as we require more than 2 * (system_page_size). In this example, it
# is evident that if the page size is 1 MB, the first index that can be used is 3.
#
# However, in most cases, these constraints do not pose a limitation, and all
# indexes from 1 to 10 can be used. You can check your system's page size using
# the Falco `--page-size` command-line option.
#
# --- [Suggestions]
#
# The buffer size was previously fixed at 8 MB (index 4). You now have the
# option to adjust the size based on your needs. Increasing the size, such as to
# 16 MB (index 5), can reduce syscall drops in heavy production systems, but may
# impact performance. Decreasing the size can speed up the system but may
# increase syscall drops. It's important to note that the buffer size is mapped
# twice in the process' virtual memory, so a buffer of 8 MB will result in a 16
# MB area in virtual memory. Use this parameter with caution and only modify it
# if the default size is not suitable for your use case.
#
################### `drop_failed_exit`
#
# --- [Description]
#
# Enabling this option in Falco allows it to drop failed system call exit events
# in the kernel drivers before pushing them onto the ring buffer. This
# optimization can result in lower CPU usage and more efficient utilization of
# the ring buffer, potentially reducing the number of event losses. However, it
# is important to note that enabling this option also means sacrificing some
# visibility into the system.
#
################### `cpus_for_each_buffer` (modern_ebpf only)
#
# --- [Description]
#
# The modern_bpf driver in Falco utilizes the new BPF ring buffer, which has a
# different memory footprint compared to the current BPF driver that uses the
# perf buffer. The Falco core maintainers have discussed the differences and
# their implications, particularly in Kubernetes environments where limits need
# to be carefully set to avoid interference with the Falco daemonset deployment
# from the OOM killer. Based on guidance received from the kernel mailing list,
# it is recommended to assign multiple CPUs to one buffer instead of allocating
# a buffer for each CPU individually. This helps optimize resource allocation
# and prevent potential issues related to memory usage.
#
# This is an index that controls how many CPUs you want to assign to a single
# syscall buffer (ring buffer). By default, for modern_bpf every syscall buffer
# is associated to 2 CPUs, so the mapping is 1:2. The modern BPF probe allows
# you to choose different mappings, for example, changing the value to `1`
# results in a 1:1 mapping and would mean one syscall buffer for each CPU (this
# is the default for the `bpf` driver).
#
# --- [Usage]
#
# You can choose an index from 0 to MAX_NUMBER_ONLINE_CPUs to set the dimension
# of the syscall buffers. The value 0 represents a single buffer shared among
# all online CPUs. It serves as a flexible option when the exact number of
# online CPUs is unknown. Here's an example to illustrate this:
#
# Consider a system with 7 online CPUs:
#
# CPUs 0 X 2 3 X X 6 7 8 9 (X means offline CPU)
#
# - `1` means a syscall buffer for each CPU so 7 buffers
#
# CPUs 0 X 2 3 X X 6 7 8 9 (X means offline CPU)
# | | | | | | |
# BUFFERs 0 1 2 3 4 5 6
#
# - `2` (Default value) means a syscall buffer for each CPU pair, so 4 buffers
#
# CPUs 0 X 2 3 X X 6 7 8 9 (X means offline CPU)
# | | | | | | |
# BUFFERs 0 0 1 1 2 2 3
#
# Please note that in this example, there are 4 buffers in total. Three of the
# buffers are associated with pairs of CPUs, while the last buffer is mapped to
# a single CPU. This arrangement is necessary because we have an odd number of
# CPUs.
#
# - `0` or `MAX_NUMBER_ONLINE_CPUs` mean a syscall buffer shared between all
# CPUs, so 1 buffer
#
# CPUs 0 X 2 3 X X 6 7 8 9 (X means offline CPU)
# | | | | | | |
# BUFFERs 0 0 0 0 0 0 0
#
# Moreover, you have the option to combine this parameter with
# `buf_size_preset` index. For instance, you can create a large shared
# syscall buffer of 512 MB (using buf_size_preset=10) that is
# allocated among all the online CPUs.
#
# --- [Suggestions]
#
# The default choice of index 2 (one syscall buffer for each CPU pair) was made
# because the modern bpf probe utilizes a different memory allocation strategy
# compared to the other two drivers (bpf and kernel module). However, you have
# the flexibility to experiment and find the optimal configuration for your
# system.
#
# When considering a fixed buf_size_preset and a fixed buffer dimension:
# - Increasing this configs value results in lower number of buffers and you can
# speed up your system and reduce memory usage
# - However, using too few buffers may increase contention in the kernel,
# leading to a slowdown.
#
# If you have low event throughputs and minimal drops, reducing the number of
# buffers (higher `cpus_for_each_buffer`) can lower the memory footprint.
#
engine:
kind: kmod
kmod:
buf_size_preset: 4
drop_failed_exit: false
ebpf:
# path to the elf file to load.
probe: ${HOME}/.falco/falco-bpf.o
buf_size_preset: 4
drop_failed_exit: false
modern_ebpf:
cpus_for_each_buffer: 2
buf_size_preset: 4
drop_failed_exit: false
replay:
# path to the capture file to replay (eg: /path/to/file.scap)
capture_file: ""
gvisor:
# A Falco-compatible configuration file can be generated with
# '--gvisor-generate-config' and utilized for both runsc and Falco.
config: ""
# 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.
root: ""
#################
# Falco plugins #
#################
@@ -170,11 +375,10 @@ rules_file:
#
# Please note that if your intention is to enrich Falco syscall logs with fields
# such as `k8s.ns.name`, `k8s.pod.name`, and `k8s.pod.*`, you do not need to use
# the `k8saudit` plugin nor the `-k`/`-K` Kubernetes metadata enrichment. This
# information is automatically extracted from the container runtime socket. The
# `k8saudit` plugin is specifically designed to integrate with Kubernetes audit
# logs and is not required for basic enrichment of syscall logs with
# Kubernetes-related fields.
# the `k8saudit` plugin. This information is automatically extracted from
# the container runtime socket. The `k8saudit` plugin is specifically designed
# to integrate with Kubernetes audit logs and is not required for basic enrichment
# of syscall logs with Kubernetes-related fields.
#
# --- [Usage]
#
@@ -273,34 +477,6 @@ json_include_tags_property: true
# output mechanism. By default, buffering is disabled (false).
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.
# The following options control the mechanism:
# - rate: the number of tokens (i.e. right to send a notification) gained per
# second. When 0, the throttling mechanism is disabled. Defaults to 0.
# - max_burst: the maximum number of tokens outstanding. Defaults to 1000.
#
# For example, setting the rate to 1 allows Falco to send up to 1000
# notifications initially, followed by 1 notification per second. The burst
# capacity is fully restored after 1000 seconds of no activity.
#
# Throttling can be useful in various scenarios, such as preventing notification
# floods, managing system load, controlling event processing, or complying with
# rate limits imposed by external systems or APIs. It allows for better resource
# utilization, avoids overwhelming downstream systems, and helps maintain a
# balanced and controlled flow of notifications.
#
# With the default settings, the throttling mechanism is disabled.
outputs:
rate: 0
max_burst: 1000
# [Experimental] `rule_matching`
#
# The `rule_matching` configuration key's values are:
@@ -322,7 +498,7 @@ outputs:
# deploying it in production.
rule_matching: first
# [Experimental] `outputs_queue`
# [Stable] `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:
@@ -406,6 +582,8 @@ http_output:
client_key: "/etc/ssl/certs/client.key"
# Whether to echo server answers to stdout
echo: false
compress_uploads: false
keep_alive: false
# [Stable] `program_output`
#
@@ -520,6 +698,8 @@ webserver:
# the appropriate number of threads based on the number of online cores in the system.
threadiness: 0
listen_port: 8765
# Can be an IPV4 or IPV6 address, defaults to IPV4
listen_address: 0.0.0.0
k8s_healthz_endpoint: /healthz
ssl_enabled: false
ssl_certificate: /etc/falco/falco.pem
@@ -613,7 +793,7 @@ output_timeout: 2000
syscall_event_timeouts:
max_consecutives: 1000
# [Stable] `syscall_event_drops`
# [Stable] `syscall_event_drops` -> [CHANGE NOTICE] Automatic notifications will be simplified in Falco 0.38! If you depend on the detailed drop counters payload, use 'metrics.output_rule' along with 'metrics.kernel_event_counters_enabled' instead
#
# Generates "Falco internal: syscall event drop" rule output when `priority=debug` at minimum
#
@@ -755,13 +935,22 @@ syscall_event_drops:
# number of CPUs to determine overall usage. Memory metrics are provided in raw
# units (`kb` for `RSS`, `PSS` and `VSZ` or `bytes` for `container_memory_used`)
# and can be uniformly converted to megabytes (MB) using the
# `convert_memory_to_mb` functionality. In environments such as Kubernetes, it
# is crucial to track Falco's container memory usage. To customize the path of
# the memory metric file, you can create an environment variable named
# `FALCO_CGROUP_MEM_PATH` and set it to the desired file path. By default, Falco
# uses the file `/sys/fs/cgroup/memory/memory.usage_in_bytes` to monitor
# container memory usage, which aligns with Kubernetes'
# `container_memory_working_set_bytes` metric.
# `convert_memory_to_mb` functionality. In environments such as Kubernetes when
# deployed as daemonset, it is crucial to track Falco's container memory usage.
# To customize the path of the memory metric file, you can create an environment
# variable named `FALCO_CGROUP_MEM_PATH` and set it to the desired file path. By
# default, Falco uses the file `/sys/fs/cgroup/memory/memory.usage_in_bytes` to
# monitor container memory usage, which aligns with Kubernetes'
# `container_memory_working_set_bytes` metric. Finally, we emit the overall host
# CPU and memory usages, along with the total number of processes and open file
# descriptors (fds) on the host, obtained from the proc file system unrelated to
# Falco's monitoring. These metrics help assess Falco's usage in relation to the
# server's workload intensity.
#
# `state_counters_enabled`: Emit counters related to Falco's state engine, including
# added, removed threads or file descriptors (fds), and failed lookup, store, or
# retrieve actions in relation to Falco's underlying process cache table (threadtable).
# We also log the number of currently cached containers if applicable.
#
# `kernel_event_counters_enabled`: Emit kernel side event and drop counters, as
# an alternative to `syscall_event_drops`, but with some differences. These
@@ -794,17 +983,21 @@ metrics:
output_rule: true
# output_file: /tmp/falco_stats.jsonl
resource_utilization_enabled: true
state_counters_enabled: true
kernel_event_counters_enabled: true
libbpf_stats_enabled: true
convert_memory_to_mb: true
include_empty_values: false
#######################################
# Falco performance tuning (advanced) #
#######################################
# [Stable] `syscall_buf_size_preset`
# [DEPRECATED] `syscall_buf_size_preset` -> Replaced by `engine.<driver>.buf_size_preset` starting Falco 0.38!
#
# Deprecated in favor of engine.{kmod,ebpf,modern_ebpf}.buf_size_preset.
# This config is evaluated only if the default `engine` config block is not changed,
# otherwise it is ignored.
#
# --- [Description]
#
@@ -856,10 +1049,14 @@ metrics:
# if the default size is not suitable for your use case.
syscall_buf_size_preset: 4
# [Experimental] `syscall_drop_failed_exit`
# [DEPRECATED] `syscall_drop_failed_exit` -> Replaced by `engine.<driver>.drop_failed_exit` starting Falco 0.38!
#
# Deprecated in favor of engine.{kmod,ebpf,modern_ebpf}.drop_failed_exit.
# This config is evaluated only if the default `engine` config block is not changed,
# otherwise it is ignored.
#
# Enabling this option in Falco allows it to drop failed system call exit events
# in the kernel driver before pushing them onto the ring buffer. This
# in the kernel drivers before pushing them onto the ring buffer. This
# optimization can result in lower CPU usage and more efficient utilization of
# the ring buffer, potentially reducing the number of event losses. However, it
# is important to note that enabling this option also means sacrificing some
@@ -981,7 +1178,11 @@ base_syscalls:
custom_set: []
repair: false
# [Stable] `modern_bpf.cpus_for_each_syscall_buffer`, modern_bpf only
# [DEPRECATED] `modern_bpf.cpus_for_each_syscall_buffer`, modern_bpf only -> Replaced by `engine.modern_ebpf.cpus_for_each_buffer` starting Falco 0.38!
#
# Deprecated in favor of engine.modern_ebpf.cpus_for_each_buffer.
# This config is evaluated only if the default `engine` config block is not changed,
# otherwise it is ignored.
#
# --- [Description]
#
@@ -1061,35 +1262,6 @@ base_syscalls:
modern_bpf:
cpus_for_each_syscall_buffer: 2
#################################################
# Falco cloud orchestration systems integration #
#################################################
# [Stable] `metadata_download`
#
# When connected to an orchestrator like Kubernetes, Falco has the capability to
# collect metadata and enrich system call events with contextual data. The
# parameters mentioned here control the downloading process of this metadata.
#
# Please note that support for Mesos is deprecated, so these parameters
# currently apply only to Kubernetes. When using Falco with Kubernetes, you can
# enable this functionality by using the `-k` or `-K` command-line flag.
#
# However, it's worth mentioning that for important Kubernetes metadata fields
# such as namespace or pod name, these fields are automatically extracted from
# the container runtime, providing the necessary enrichment for common use cases
# of syscall-based threat detection.
#
# In summary, the `-k` flag is typically not required for most scenarios involving
# Kubernetes workload owner enrichment. The `-k` flag is primarily used when
# additional metadata is required beyond the standard fields, catering to more
# specific use cases, see https://falco.org/docs/reference/rules/supported-fields/#field-class-k8s.
metadata_download:
max_mb: 100
chunk_wait_us: 1000
watch_freq_sec: 1
# [Stable] Guidance for Kubernetes container engine command-line args settings
#
# Modern cloud environments, particularly Kubernetes, heavily rely on

View File

@@ -41,11 +41,6 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux")
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
@@ -53,5 +48,6 @@ 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}")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/falcoctl/falcoctl.yaml.in ${PROJECT_BINARY_DIR}/scripts/falcoctl/falcoctl.yaml)
install(FILES ${PROJECT_BINARY_DIR}/scripts/falcoctl/falcoctl.yaml DESTINATION "${FALCOCTL_ETC_DIR}" COMPONENT "${FALCO_COMPONENT_NAME}")
endif()

View File

@@ -18,6 +18,8 @@
#
chosen_driver=
chosen_unit=
CHOICE=
# Every time we call this script we want to stat from a clean state.
echo "[POST-INSTALL] Disable all possible 'falco' services:"
@@ -36,39 +38,63 @@ systemctl --system disable 'falcoctl-artifact-follow.service' || true
systemctl --system unmask falcoctl-artifact-follow.service || true
if [ "$1" = "configure" ]; then
if [ -x /usr/bin/dialog ] && [ "${FALCO_FRONTEND}" != "noninteractive" ]; then
# If dialog is installed, create a dialog to let users choose the correct driver for them
CHOICE=$(dialog --clear --title "Falco drivers" --menu "Choose your preferred driver:" 12 55 4 \
1 "Manual configuration (no unit is started)" \
2 "Kmod" \
3 "eBPF" \
4 "Modern eBPF" \
2>&1 >/dev/tty)
case $CHOICE in
2)
chosen_driver="kmod"
;;
3)
chosen_driver="bpf"
;;
4)
chosen_driver="modern-bpf"
;;
esac
if [ -n "$chosen_driver" ]; then
CHOICE=$(dialog --clear --title "Falcoctl" --menu "Do you want to follow automatic ruleset updates?" 10 40 2 \
1 "Yes" \
2 "No" \
case $FALCO_DRIVER_CHOICE in
kmod)
CHOICE=2
;;
ebpf)
CHOICE=3
;;
modern_ebpf)
CHOICE=4
;;
esac
if [ -z $CHOICE ] && [ -x /usr/bin/dialog ] && [ "${FALCO_FRONTEND}" != "noninteractive" ]; then
# If dialog is installed, create a dialog to let users choose the correct driver for them
CHOICE=$(dialog --clear --title "Falco drivers" --menu "Choose your preferred driver:" 12 55 4 \
1 "Manual configuration (no unit is started)" \
2 "Kmod" \
3 "eBPF" \
4 "Modern eBPF" \
2>&1 >/dev/tty)
fi
case $CHOICE in
2)
chosen_driver="kmod"
chosen_unit="kmod"
;;
3)
chosen_driver="ebpf"
chosen_unit="bpf"
;;
4)
chosen_driver="modern_ebpf"
chosen_unit="modern-bpf"
;;
esac
if [ -n "$CHOICE" ]; then
echo "[POST-INSTALL] Configure falcoctl driver type:"
falcoctl driver config --type $chosen_driver
CHOICE=
case $FALCOCTL_ENABLED in
no)
CHOICE=2
;;
esac
if [ -z $CHOICE ] && [ -x /usr/bin/dialog ] && [ "${FALCO_FRONTEND}" != "noninteractive" ]; then
CHOICE=$(dialog --clear --title "Falcoctl" --menu "Do you want to follow automatic ruleset updates?" 10 40 2 \
1 "Yes" \
2 "No" \
2>&1 >/dev/tty)
fi
case $CHOICE in
2)
# we don't want falcoctl enabled, we mask it
systemctl --system mask falcoctl-artifact-follow.service || true
# we don't want falcoctl enabled, we mask it
systemctl --system mask falcoctl-artifact-follow.service || true
;;
esac
fi
clear
fi
fi
clear
fi
set -e
@@ -76,25 +102,25 @@ set -e
echo "[POST-INSTALL] Trigger deamon-reload:"
systemctl --system daemon-reload || true
# If needed, try to load/compile the driver through falco-driver-loader
# If needed, try to load/compile the driver through falcoctl
case "$chosen_driver" in
"kmod")
# Only compile for kmod, in this way we use dkms
echo "[POST-INSTALL] Call 'falco-driver-loader --compile module':"
falco-driver-loader --compile module
echo "[POST-INSTALL] Call 'falcoctl driver install for kmod:"
falcoctl driver install --download=false
;;
"bpf")
echo "[POST-INSTALL] Call 'falco-driver-loader bpf':"
falco-driver-loader bpf
"ebpf")
echo "[POST-INSTALL] Call 'falcoctl driver install for ebpf':"
falcoctl driver install
;;
esac
if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-deconfigure" ] || [ "$1" = "abort-remove" ] ; then
if [ -n "$chosen_driver" ]; then
if [ -n "$chosen_unit" ]; then
# we do this in 2 steps because `enable --now` is not always supported
echo "[POST-INSTALL] Enable 'falco-$chosen_driver.service':"
systemctl --system enable "falco-$chosen_driver.service" || true
echo "[POST-INSTALL] Start 'falco-$chosen_driver.service':"
systemctl --system start "falco-$chosen_driver.service" || true
echo "[POST-INSTALL] Enable 'falco-$chosen_unit.service':"
systemctl --system enable "falco-$chosen_unit.service" || true
echo "[POST-INSTALL] Start 'falco-$chosen_unit.service':"
systemctl --system start "falco-$chosen_unit.service" || true
fi
fi

View File

@@ -31,7 +31,7 @@ case "$1" in
systemctl --system stop 'falco-custom.service' || true
systemctl --system stop 'falcoctl-artifact-follow.service' || true
echo "[PRE-REMOVE] Call 'falco-driver-loader --clean:'"
falco-driver-loader --clean
echo "[PRE-REMOVE] Call 'falcoctl driver cleanup:'"
falcoctl driver cleanup
;;
esac

View File

@@ -1,866 +0,0 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: Apache-2.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.
#
# Simple script that desperately tries to load the kernel instrumentation by
# looking for it in a bunch of ways. Convenient when running Falco inside
# a container or in other weird environments.
#
#
# Returns 1 if $cos_ver > $base_ver, 0 otherwise
#
cos_version_greater() {
if [[ $cos_ver == "${base_ver}" ]]; then
return 0
fi
#
# COS build numbers are in the format x.y.z
#
a=$(echo "${cos_ver}" | cut -d. -f1)
b=$(echo "${cos_ver}" | cut -d. -f2)
c=$(echo "${cos_ver}" | cut -d. -f3)
d=$(echo "${base_ver}" | cut -d. -f1)
e=$(echo "${base_ver}" | cut -d. -f2)
f=$(echo "${base_ver}" | cut -d. -f3)
# Test the first component
if [[ $a -gt $d ]]; then
return 1
elif [[ $d -gt $a ]]; then
return 0
fi
# Test the second component
if [[ $b -gt $e ]]; then
return 1
elif [[ $e -gt $b ]]; then
return 0
fi
# Test the third component
if [[ $c -gt $f ]]; then
return 1
elif [[ $f -gt $c ]]; then
return 0
fi
# If we get here, probably malformatted version string?
return 0
}
get_kernel_config() {
if [ -f /proc/config.gz ]; then
echo "* Found kernel config at /proc/config.gz"
KERNEL_CONFIG_PATH=/proc/config.gz
elif [ -f "/boot/config-${KERNEL_RELEASE}" ]; then
echo "* Found kernel config at /boot/config-${KERNEL_RELEASE}"
KERNEL_CONFIG_PATH=/boot/config-${KERNEL_RELEASE}
elif [ -n "${HOST_ROOT}" ] && [ -f "${HOST_ROOT}/boot/config-${KERNEL_RELEASE}" ]; then
echo "* Found kernel config at ${HOST_ROOT}/boot/config-${KERNEL_RELEASE}"
KERNEL_CONFIG_PATH="${HOST_ROOT}/boot/config-${KERNEL_RELEASE}"
elif [ -f "/usr/lib/ostree-boot/config-${KERNEL_RELEASE}" ]; then
echo "* Found kernel config at /usr/lib/ostree-boot/config-${KERNEL_RELEASE}"
KERNEL_CONFIG_PATH="/usr/lib/ostree-boot/config-${KERNEL_RELEASE}"
elif [ -n "${HOST_ROOT}" ] && [ -f "${HOST_ROOT}/usr/lib/ostree-boot/config-${KERNEL_RELEASE}" ]; then
echo "* Found kernel config at ${HOST_ROOT}/usr/lib/ostree-boot/config-${KERNEL_RELEASE}"
KERNEL_CONFIG_PATH="${HOST_ROOT}/usr/lib/ostree-boot/config-${KERNEL_RELEASE}"
elif [ -f "/lib/modules/${KERNEL_RELEASE}/config" ]; then
# This code works both for native host and containers assuming that
# Dockerfile sets up the desired symlink /lib/modules -> $HOST_ROOT/lib/modules
echo "* Found kernel config at /lib/modules/${KERNEL_RELEASE}/config"
KERNEL_CONFIG_PATH="/lib/modules/${KERNEL_RELEASE}/config"
fi
if [ -z "${KERNEL_CONFIG_PATH}" ]; then
>&2 echo "Cannot find kernel config"
exit 1
fi
if [[ "${KERNEL_CONFIG_PATH}" == *.gz ]]; then
HASH=$(zcat "${KERNEL_CONFIG_PATH}" | md5sum - | cut -d' ' -f1)
else
HASH=$(md5sum "${KERNEL_CONFIG_PATH}" | cut -d' ' -f1)
fi
}
get_target_id() {
if [ -f "${HOST_ROOT}/etc/os-release" ]; then
# freedesktop.org and systemd
# shellcheck source=/dev/null
source "${HOST_ROOT}/etc/os-release"
OS_ID=$ID
elif [ -f "${HOST_ROOT}/etc/debian_version" ]; then
# Older debian distros
# fixme > Can this happen on older Ubuntu?
OS_ID=debian
elif [ -f "${HOST_ROOT}/etc/centos-release" ]; then
# Older CentOS distros
OS_ID=centos
elif [ -f "${HOST_ROOT}/etc/redhat-release" ]; then
# Older RHEL distros
OS_ID=rhel
else
# No target id can be determinand
TARGET_ID="undetermined"
return
fi
# Overwrite the OS_ID if /etc/VERSION file is present.
# Not sure if there is a better way to detect minikube.
if [ -f "${HOST_ROOT}/etc/VERSION" ]; then
OS_ID=minikube
fi
case "${OS_ID}" in
("amzn")
case "${VERSION_ID}" in
("2")
TARGET_ID="amazonlinux2"
;;
("2022")
TARGET_ID="amazonlinux2022"
;;
("2023")
TARGET_ID="amazonlinux2023"
;;
(*)
TARGET_ID="amazonlinux"
;;
esac
;;
("debian")
# Workaround: debian kernelreleases might now be actual kernel running;
# instead, they might be the Debian kernel package
# providing the compatible kernel ABI
# See https://lists.debian.org/debian-user/2017/03/msg00485.html
# Real kernel release is embedded inside the kernel version.
# Moreover, kernel arch, when present, is attached to the former,
# therefore make sure to properly take it and attach it to the latter.
# Moreover, we support 3 flavors for debian kernels: cloud, rt and normal.
# KERNEL-RELEASE will have a `-rt`, or `-cloud` if we are in one of these flavors.
# Manage it to download the correct driver.
#
# Example: KERNEL_RELEASE="5.10.0-0.deb10.22-rt-amd64" and `uname -v`="5.10.178-3"
# should lead to: KERNEL_RELEASE="5.10.178-3-rt-amd64"
TARGET_ID=$(echo "${OS_ID}" | tr '[:upper:]' '[:lower:]')
local ARCH_extra=""
if [[ $KERNEL_RELEASE =~ -?(rt-|cloud-|)(amd64|arm64) ]];
then
ARCH_extra="-${BASH_REMATCH[1]}${BASH_REMATCH[2]}"
fi
if [[ ${DRIVER_KERNEL_VERSION} =~ ([0-9]+\.[0-9]+\.[0-9]+\-[0-9]+) ]];
then
KERNEL_RELEASE="${BASH_REMATCH[1]}${ARCH_extra}"
fi
;;
("ubuntu")
# Extract the flavor from the kernelrelease
# Examples:
# 5.0.0-1028-aws-5.0 -> ubuntu-aws
# 5.15.0-1009-aws -> ubuntu-aws
if [[ $KERNEL_RELEASE =~ -([a-zA-Z]+)(-.*)?$ ]];
then
TARGET_ID="ubuntu-${BASH_REMATCH[1]}"
else
TARGET_ID="ubuntu-generic"
fi
# In the case that the kernelversion isn't just a number
# we keep also the remaining part excluding `-Ubuntu`.
# E.g.:
# 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 [[ ${DRIVER_KERNEL_VERSION} =~ (^\#[0-9]+\~[^-]*-Ubuntu .*$) ]];
then
KERNEL_VERSION=$(echo "${DRIVER_KERNEL_VERSION}" | sed 's/#\([^-\\ ]*\).*/\1/g')
fi
;;
("flatcar")
KERNEL_RELEASE="${VERSION_ID}"
TARGET_ID=$(echo "${OS_ID}" | tr '[:upper:]' '[:lower:]')
;;
("minikube")
TARGET_ID=$(echo "${OS_ID}" | tr '[:upper:]' '[:lower:]')
# Extract the minikube version. Ex. With minikube version equal to "v1.26.0-1655407986-14197" the extracted version
# will be "1.26.0"
if [[ $(cat ${HOST_ROOT}/etc/VERSION) =~ ([0-9]+(\.[0-9]+){2}) ]]; then
# kernel version for minikube is always in "1_minikubeversion" format. Ex "1_1.26.0".
KERNEL_VERSION="1_${BASH_REMATCH[1]}"
else
echo "* Unable to extract minikube version from ${HOST_ROOT}/etc/VERSION"
exit 1
fi
;;
("bottlerocket")
TARGET_ID=$(echo "${OS_ID}" | tr '[:upper:]' '[:lower:]')
# variant_id has been sourced from os-release. Get only the first variant part
if [[ -n ${VARIANT_ID} ]]; then
# take just first part (eg: VARIANT_ID=aws-k8s-1.15 -> aws)
VARIANT_ID_CUT=${VARIANT_ID%%-*}
fi
# version_id has been sourced from os-release. Build a kernel version like: 1_1.11.0-aws
KERNEL_VERSION="1_${VERSION_ID}-${VARIANT_ID_CUT}"
;;
("talos")
TARGET_ID=$(echo "${OS_ID}" | tr '[:upper:]' '[:lower:]')
# version_id has been sourced from os-release. Build a kernel version like: 1_1.4.1
KERNEL_VERSION="1_${VERSION_ID}"
;;
(*)
TARGET_ID=$(echo "${OS_ID}" | tr '[:upper:]' '[:lower:]')
;;
esac
}
flatcar_relocate_tools() {
local -a tools=(
scripts/basic/fixdep
scripts/mod/modpost
tools/objtool/objtool
)
local -r hostld=$(ls /host/usr/lib64/ld-linux-*.so.*)
local -r kdir=/lib/modules/$(ls /lib/modules/)/build
echo "** Found host dl interpreter: ${hostld}"
for host_tool in ${tools[@]}; do
t=${host_tool}
tool=$(basename $t)
tool_dir=$(dirname $t)
host_tool=${kdir}/${host_tool}
if [ ! -f ${host_tool} ]; then
continue
fi
umount ${host_tool} 2>/dev/null || true
mkdir -p /tmp/${tool_dir}/
cp -a ${host_tool} /tmp/${tool_dir}/
echo "** Setting host dl interpreter for $host_tool"
patchelf --set-interpreter ${hostld} --set-rpath /host/usr/lib64 /tmp/${tool_dir}/${tool}
mount -o bind /tmp/${tool_dir}/${tool} ${host_tool}
done
}
load_kernel_module_compile() {
# Skip dkms on UEK hosts because it will always fail
if [[ ${DRIVER_KERNEL_RELEASE} == *uek* ]]; then
>&2 echo "Skipping because the dkms install always fail (on UEK hosts)"
return
fi
if ! hash dkms >/dev/null 2>&1; then
>&2 echo "This program requires dkms"
return
fi
if [ "${TARGET_ID}" == "flatcar" ]; then
KERNEL_RELEASE=${DRIVER_KERNEL_RELEASE}
echo "* Flatcar detected (version ${VERSION_ID}); relocating kernel tools"
flatcar_relocate_tools
fi
# Try to compile using all the available gcc versions
for CURRENT_GCC in $(ls "$(dirname "$(which gcc)")"/gcc*); do
# Filter away gcc-{ar,nm,...}
# Only gcc compiler has `-print-search-dirs` option.
${CURRENT_GCC} -print-search-dirs 2>&1 | grep "install:"
if [ "$?" -ne "0" ]; then
continue
fi
echo "* Trying to dkms install ${DRIVER_NAME} module with GCC ${CURRENT_GCC}"
echo "#!/usr/bin/env bash" > "${TMPDIR}/falco-dkms-make"
echo "make CC=${CURRENT_GCC} \$@" >> "${TMPDIR}/falco-dkms-make"
chmod +x "${TMPDIR}/falco-dkms-make"
if dkms install --directive="MAKE='${TMPDIR}/falco-dkms-make'" -m "${DRIVER_NAME}" -v "${DRIVER_VERSION}" -k "${KERNEL_RELEASE}" 2>/dev/null; then
echo "* ${DRIVER_NAME} module installed in dkms"
KO_FILE="/var/lib/dkms/${DRIVER_NAME}/${DRIVER_VERSION}/${KERNEL_RELEASE}/${ARCH}/module/${DRIVER_NAME}"
if [ -f "$KO_FILE.ko" ]; then
KO_FILE="$KO_FILE.ko"
elif [ -f "$KO_FILE.ko.gz" ]; then
KO_FILE="$KO_FILE.ko.gz"
elif [ -f "$KO_FILE.ko.xz" ]; then
KO_FILE="$KO_FILE.ko.xz"
elif [ -f "$KO_FILE.ko.zst" ]; then
KO_FILE="$KO_FILE.ko.zst"
else
>&2 echo "${DRIVER_NAME} module file not found"
return
fi
echo "* ${DRIVER_NAME} module found: ${KO_FILE}"
echo "* Trying to insmod"
chcon -t modules_object_t "$KO_FILE" > /dev/null 2>&1 || true
if insmod "$KO_FILE" > /dev/null 2>&1; then
echo "* Success: ${DRIVER_NAME} module found and loaded in dkms"
exit 0
fi
echo "* Unable to insmod ${DRIVER_NAME} module"
else
DKMS_LOG="/var/lib/dkms/${DRIVER_NAME}/${DRIVER_VERSION}/build/make.log"
if [ -f "${DKMS_LOG}" ]; then
echo "* Running dkms build failed, dumping ${DKMS_LOG} (with GCC ${CURRENT_GCC})"
cat "${DKMS_LOG}"
else
echo "* Running dkms build failed, couldn't find ${DKMS_LOG} (with GCC ${CURRENT_GCC})"
fi
fi
done
}
load_kernel_module_download() {
local FALCO_KERNEL_MODULE_FILENAME="${DRIVER_NAME}_${TARGET_ID}_${KERNEL_RELEASE}_${KERNEL_VERSION}.ko"
local URL=$(echo "${1}/${DRIVER_VERSION}/${ARCH}/${FALCO_KERNEL_MODULE_FILENAME}" | sed s/+/%2B/g)
echo "* Trying to download a prebuilt ${DRIVER_NAME} module from ${URL}"
if curl -L --create-dirs ${FALCO_DRIVER_CURL_OPTIONS} -o "${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${FALCO_KERNEL_MODULE_FILENAME}" "${URL}"; then
echo "* Download succeeded"
chcon -t modules_object_t "${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${FALCO_KERNEL_MODULE_FILENAME}" > /dev/null 2>&1 || true
if insmod "${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${FALCO_KERNEL_MODULE_FILENAME}"; then
echo "* Success: ${DRIVER_NAME} module found and inserted"
exit 0
fi
>&2 echo "Unable to insmod the prebuilt ${DRIVER_NAME} module"
else
>&2 echo "Unable to find a prebuilt ${DRIVER_NAME} module"
return
fi
}
print_clean_termination() {
echo
echo "[SUCCESS] Cleaning phase correctly terminated."
echo
echo "================ Cleaning phase ================"
echo
}
print_filename_components() {
echo " - driver name: ${DRIVER_NAME}"
echo " - target identifier: ${TARGET_ID}"
echo " - kernel release: ${KERNEL_RELEASE}"
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 "================ Cleaning phase ================"
echo
if ! hash lsmod > /dev/null 2>&1; then
>&2 echo "This program requires lsmod."
exit 1
fi
if ! hash rmmod > /dev/null 2>&1; then
>&2 echo "This program requires rmmod."
exit 1
fi
KMOD_NAME=$(echo "${DRIVER_NAME}" | tr "-" "_")
echo "* 1. Check if kernel module '${KMOD_NAME}' is still loaded:"
if ! lsmod | cut -d' ' -f1 | grep -qx "${KMOD_NAME}"; then
echo "- OK! There is no '${KMOD_NAME}' module loaded."
echo
fi
# Wait 50s = MAX_RMMOD_WAIT * 5s
MAX_RMMOD_WAIT=10
# Remove kernel module if is still loaded.
while lsmod | cut -d' ' -f1 | grep -qx "${KMOD_NAME}" && [ $MAX_RMMOD_WAIT -gt 0 ]; do
echo "- Kernel module '${KMOD_NAME}' is still loaded."
echo "- Trying to unload it with 'rmmod ${KMOD_NAME}'..."
if rmmod ${KMOD_NAME}; then
echo "- OK! Unloading '${KMOD_NAME}' module succeeded."
echo
else
echo "- Nothing to do...'falco-driver-loader' will wait until you remove the kernel module to have a clean termination."
echo "- Check that no process is using the kernel module with 'lsmod | grep ${KMOD_NAME}'."
echo "- Sleep 5 seconds..."
echo
((--MAX_RMMOD_WAIT))
sleep 5
fi
done
if [ ${MAX_RMMOD_WAIT} -eq 0 ]; then
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
return
fi
# Remove all versions of this module from dkms.
echo "* 2. Check all versions of kernel module '${KMOD_NAME}' in dkms:"
DRIVER_VERSIONS=$(dkms status -m "${KMOD_NAME}" | tr -d "," | tr -d ":" | tr "/" " " | cut -d' ' -f2)
if [ -z "${DRIVER_VERSIONS}" ]; then
echo "- OK! There are no '${KMOD_NAME}' module versions in dkms."
else
echo "- There are some versions of '${KMOD_NAME}' module in dkms."
echo
echo "* 3. Removing all the following versions from dkms:"
echo "${DRIVER_VERSIONS}"
echo
fi
for CURRENT_VER in ${DRIVER_VERSIONS}; do
echo "- Removing ${CURRENT_VER}..."
if dkms remove -m ${KMOD_NAME} -v "${CURRENT_VER}" --all; then
echo
echo "- OK! Removing '${CURRENT_VER}' succeeded."
echo
else
echo "[WARNING] Removing '${KMOD_NAME}' version '${CURRENT_VER}' failed."
fi
done
print_clean_termination
}
load_kernel_module() {
clean_kernel_module
echo "* Looking for a ${DRIVER_NAME} module locally (kernel ${KERNEL_RELEASE})"
local FALCO_KERNEL_MODULE_FILENAME="${DRIVER_NAME}_${TARGET_ID}_${KERNEL_RELEASE}_${KERNEL_VERSION}.ko"
echo "* Filename '${FALCO_KERNEL_MODULE_FILENAME}' is composed of:"
print_filename_components
if [ -f "${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${FALCO_KERNEL_MODULE_FILENAME}" ]; then
echo "* Found a prebuilt ${DRIVER_NAME} module at ${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${FALCO_KERNEL_MODULE_FILENAME}, loading it"
chcon -t modules_object_t "${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${FALCO_KERNEL_MODULE_FILENAME}" > /dev/null 2>&1 || true
insmod "${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${FALCO_KERNEL_MODULE_FILENAME}" && echo "* Success: ${DRIVER_NAME} module found and inserted"
exit $?
fi
if [ -n "$ENABLE_DOWNLOAD" ]; then
IFS=", " read -r -a urls <<< "${DRIVERS_REPO}"
for url in "${urls[@]}"; do
load_kernel_module_download $url
done
fi
if [ -n "$ENABLE_COMPILE" ]; then
load_kernel_module_compile
fi
# Last try (might load a previous driver version)
echo "* Trying to load a system ${DRIVER_NAME} module, if present"
if modprobe "${DRIVER_NAME}" > /dev/null 2>&1; then
echo "* Success: ${DRIVER_NAME} module found and loaded with modprobe"
exit 0
fi
# Not able to download a prebuilt module nor to compile one on-the-fly
>&2 echo "Consider compiling your own ${DRIVER_NAME} driver and loading it or getting in touch with the Falco community"
exit 1
}
load_bpf_probe_compile() {
local BPF_KERNEL_SOURCES_URL=""
local STRIP_COMPONENTS=1
customize_kernel_build() {
if [ -n "${KERNEL_EXTRA_VERSION}" ]; then
sed -i "s/LOCALVERSION=\"\"/LOCALVERSION=\"${KERNEL_EXTRA_VERSION}\"/" .config
fi
make olddefconfig > /dev/null
make modules_prepare > /dev/null
}
if [ "${TARGET_ID}" == "flatcar" ]; then
KERNEL_RELEASE=${DRIVER_KERNEL_RELEASE}
echo "* Flatcar detected (version ${VERSION_ID}); relocating kernel tools"
flatcar_relocate_tools
fi
if [ "${TARGET_ID}" == "cos" ]; then
echo "* COS detected (build ${BUILD_ID}), using COS kernel headers"
BPF_KERNEL_SOURCES_URL="https://storage.googleapis.com/cos-tools/${BUILD_ID}/kernel-headers.tgz"
KERNEL_EXTRA_VERSION="+"
STRIP_COMPONENTS=0
customize_kernel_build() {
pushd usr/src/* > /dev/null || exit
# Note: this overrides the KERNELDIR set while untarring the tarball
KERNELDIR=$(pwd)
export KERNELDIR
sed -i '/^#define randomized_struct_fields_start struct {$/d' include/linux/compiler-clang.h
sed -i '/^#define randomized_struct_fields_end };$/d' include/linux/compiler-clang.h
popd > /dev/null || exit
# Might need to configure our own sources depending on COS version
cos_ver=${BUILD_ID}
base_ver=11553.0.0
cos_version_greater
greater_ret=$?
if [[ greater_ret -eq 1 ]]; then
export KBUILD_EXTRA_CPPFLAGS=-DCOS_73_WORKAROUND
fi
}
fi
if [ "${TARGET_ID}" == "minikube" ]; then
MINIKUBE_VERSION="$(cat "${HOST_ROOT}/etc/VERSION")"
echo "* Minikube detected (${MINIKUBE_VERSION}), using linux kernel sources for minikube kernel"
local kernel_version
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)
if [ "${kernel_version_patch}" == "0" ]; then
kernel_version="${kernel_version_major}.${kernel_version_minor}"
fi
BPF_KERNEL_SOURCES_URL="http://mirrors.edge.kernel.org/pub/linux/kernel/v${kernel_version_major}.x/linux-${kernel_version}.tar.gz"
fi
if [ -n "${BPF_USE_LOCAL_KERNEL_SOURCES}" ]; then
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}..."
BPF_KERNEL_SOURCES_URL="http://mirrors.edge.kernel.org/pub/linux/kernel/v${kernel_version_major}.x/linux-${kernel_version}.tar.gz"
fi
if [ -n "${BPF_KERNEL_SOURCES_URL}" ]; then
get_kernel_config
echo "* Downloading ${BPF_KERNEL_SOURCES_URL}"
mkdir -p /tmp/kernel
cd /tmp/kernel || exit
cd "$(mktemp -d -p /tmp/kernel)" || exit
if ! curl -L -o kernel-sources.tgz --create-dirs ${FALCO_DRIVER_CURL_OPTIONS} "${BPF_KERNEL_SOURCES_URL}"; then
>&2 echo "Unable to download the kernel sources"
return
fi
echo "* Extracting kernel sources"
mkdir kernel-sources && tar xf kernel-sources.tgz -C kernel-sources --strip-components "${STRIP_COMPONENTS}"
cd kernel-sources || exit
KERNELDIR=$(pwd)
export KERNELDIR
if [[ "${KERNEL_CONFIG_PATH}" == *.gz ]]; then
zcat "${KERNEL_CONFIG_PATH}" > .config
else
cat "${KERNEL_CONFIG_PATH}" > .config
fi
echo "* Configuring kernel"
customize_kernel_build
fi
echo "* Trying to compile the eBPF probe (${BPF_PROBE_FILENAME})"
make -C "/usr/src/${DRIVER_NAME}-${DRIVER_VERSION}/bpf" > /dev/null
mkdir -p "${HOME}/.falco/${DRIVER_VERSION}/${ARCH}"
mv "/usr/src/${DRIVER_NAME}-${DRIVER_VERSION}/bpf/probe.o" "${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${BPF_PROBE_FILENAME}"
if [ -n "${BPF_KERNEL_SOURCES_URL}" ]; then
rm -r /tmp/kernel
fi
}
load_bpf_probe_download() {
local URL
URL=$(echo "${1}/${DRIVER_VERSION}/${ARCH}/${BPF_PROBE_FILENAME}" | sed s/+/%2B/g)
echo "* Trying to download a prebuilt eBPF probe from ${URL}"
if ! curl -L --create-dirs ${FALCO_DRIVER_CURL_OPTIONS} -o "${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${BPF_PROBE_FILENAME}" "${URL}"; then
>&2 echo "Unable to find a prebuilt ${DRIVER_NAME} eBPF probe"
return 1
fi
return 0
}
load_bpf_probe() {
if [ ! -d /sys/kernel/debug/tracing ]; then
echo "* Mounting debugfs"
mount -t debugfs nodev /sys/kernel/debug
fi
BPF_PROBE_FILENAME="${DRIVER_NAME}_${TARGET_ID}_${KERNEL_RELEASE}_${KERNEL_VERSION}.o"
echo "* Filename '${BPF_PROBE_FILENAME}' is composed of:"
print_filename_components
if [ -n "$ENABLE_DOWNLOAD" ]; then
if [ -f "${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${BPF_PROBE_FILENAME}" ]; then
echo "* Skipping download, eBPF probe is already present in ${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${BPF_PROBE_FILENAME}"
else
IFS=", " read -r -a urls <<< "${DRIVERS_REPO}"
for url in "${urls[@]}"; do
load_bpf_probe_download $url
if [ $? -eq 0 ]; then
break
fi
done
fi
fi
if [ -n "$ENABLE_COMPILE" ]; then
if [ -f "${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${BPF_PROBE_FILENAME}" ]; then
echo "* Skipping compilation, eBPF probe is already present in ${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${BPF_PROBE_FILENAME}"
else
load_bpf_probe_compile
fi
fi
if [ -f "${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${BPF_PROBE_FILENAME}" ]; then
echo "* eBPF probe located in ${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${BPF_PROBE_FILENAME}"
ln -sf "${HOME}/.falco/${DRIVER_VERSION}/${ARCH}/${BPF_PROBE_FILENAME}" "${HOME}/.falco/${DRIVER_NAME}-bpf.o" \
&& echo "* Success: eBPF probe symlinked to ${HOME}/.falco/${DRIVER_NAME}-bpf.o"
exit $?
else
>&2 echo "Unable to load the ${DRIVER_NAME} eBPF probe"
exit 1
fi
}
print_usage() {
echo ""
echo "Usage:"
echo " falco-driver-loader [driver] [options]"
echo ""
echo "Available drivers:"
echo " module kernel module (default)"
echo " bpf eBPF probe"
echo ""
echo "Options:"
echo " --help show brief help"
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 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}"
echo " Driver version ${DRIVER_VERSION}"
echo ""
}
ARCH=$(uname -m)
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
DRIVER_KERNEL_VERSION=${DRIVER_KERNEL_VERSION:-$(uname -v)}
KERNEL_VERSION=$(echo "${DRIVER_KERNEL_VERSION}" | sed 's/#\([[:digit:]]\+\).*/\1/')
DRIVERS_REPO=${DRIVERS_REPO:-"@DRIVERS_REPO@"}
FALCO_DRIVER_CURL_OPTIONS="-fsS --connect-timeout 5 --max-time 60 --retry 3 --retry-max-time 120"
if [ -n "$DRIVER_INSECURE_DOWNLOAD" ]
then
FALCO_DRIVER_CURL_OPTIONS+=" -k"
fi
FALCO_DRIVER_CURL_OPTIONS+=" "${DRIVER_CURL_OPTIONS}
if [[ -z "$MAX_RMMOD_WAIT" ]]; then
MAX_RMMOD_WAIT=60
fi
DRIVER_VERSION=${DRIVER_VERSION:-"@DRIVER_VERSION@"}
DRIVER_NAME=${DRIVER_NAME:-"@DRIVER_NAME@"}
FALCO_VERSION="@FALCO_VERSION@"
TARGET_ID=
get_target_id
DRIVER="module"
if [ -v FALCO_BPF_PROBE ]; then
DRIVER="bpf"
fi
TMPDIR=${TMPDIR:-"/tmp"}
ENABLE_COMPILE=
ENABLE_DOWNLOAD=
clean=
has_args=
has_opts=
print_env=
source_only=
while test $# -gt 0; do
case "$1" in
module|bpf)
if [ -n "$has_args" ]; then
>&2 echo "Only one driver per invocation"
print_usage
exit 1
else
DRIVER="$1"
has_args="true"
shift
fi
;;
-h|--help)
print_usage
exit 0
;;
--clean)
clean="true"
shift
;;
--compile)
ENABLE_COMPILE="yes"
has_opts="true"
shift
;;
--download)
ENABLE_DOWNLOAD="yes"
has_opts="true"
shift
;;
--source-only)
source_only="true"
shift
;;
--print-env)
print_env="true"
shift
;;
--*)
>&2 echo "Unknown option: $1"
print_usage
exit 1
;;
*)
>&2 echo "Unknown driver: $1"
print_usage
exit 1
;;
esac
done
if [ -z "$has_opts" ]; then
ENABLE_COMPILE="yes"
ENABLE_DOWNLOAD="yes"
fi
if [ -n "$source_only" ]; then
# Return or exit, depending if we've been sourced.
(return 0 2>/dev/null) && return || exit 0
fi
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
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
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

View File

@@ -1,3 +1,10 @@
driver:
type: "kmod"
name: "@DRIVER_NAME@"
repos:
- "@DRIVERS_REPO@"
version: "@DRIVER_VERSION@"
hostroot: "/"
artifact:
follow:
every: 6h0m0s

View File

@@ -17,6 +17,8 @@
#
chosen_driver=
chosen_unit=
CHOICE=
# Every time we call this script we want to stat from a clean state.
echo "[POST-INSTALL] Disable all possible enabled 'falco' service:"
@@ -35,7 +37,18 @@ systemctl --system disable 'falcoctl-artifact-follow.service' || true
systemctl --system unmask falcoctl-artifact-follow.service || true
if [ $1 -ge 1 ]; then
if [ -x /usr/bin/dialog ] && [ "${FALCO_FRONTEND}" != "noninteractive" ]; then
case $FALCO_DRIVER_CHOICE in
kmod)
CHOICE=2
;;
ebpf)
CHOICE=3
;;
modern_ebpf)
CHOICE=4
;;
esac
if [ -z $CHOICE ] && [ -x /usr/bin/dialog ] && [ "${FALCO_FRONTEND}" != "noninteractive" ]; then
# If dialog is installed, create a dialog to let users choose the correct driver for them
CHOICE=$(dialog --clear --title "Falco drivers" --menu "Choose your preferred driver:" 12 55 4 \
1 "Manual configuration (no unit is started)" \
@@ -43,31 +56,44 @@ if [ $1 -ge 1 ]; then
3 "eBPF" \
4 "Modern eBPF" \
2>&1 >/dev/tty)
case $CHOICE in
2)
chosen_driver="kmod"
;;
3)
chosen_driver="bpf"
;;
4)
chosen_driver="modern-bpf"
fi
case $CHOICE in
2)
chosen_driver="kmod"
chosen_unit="kmod"
;;
3)
chosen_driver="ebpf"
chosen_unit="bpf"
;;
4)
chosen_driver="modern_ebpf"
chosen_unit="modern-bpf"
;;
esac
if [ -n "$CHOICE" ]; then
echo "[POST-INSTALL] Configure falcoctl driver type:"
falcoctl driver config --type $chosen_driver
CHOICE=
case $FALCOCTL_ENABLED in
no)
CHOICE=2
;;
esac
if [ -n "$chosen_driver" ]; then
CHOICE=$(dialog --clear --title "Falcoctl" --menu "Do you want to follow automatic ruleset updates?" 10 40 2 \
1 "Yes" \
2 "No" \
2>&1 >/dev/tty)
case $CHOICE in
2)
# we don't want falcoctl enabled, we mask it
systemctl --system mask falcoctl-artifact-follow.service || true
;;
esac
fi
clear
fi
if [ -z $CHOICE ] && [ -x /usr/bin/dialog ] && [ "${FALCO_FRONTEND}" != "noninteractive" ]; then
CHOICE=$(dialog --clear --title "Falcoctl" --menu "Do you want to follow automatic ruleset updates?" 10 40 2 \
1 "Yes" \
2 "No" \
2>&1 >/dev/tty)
fi
case $CHOICE in
2)
# we don't want falcoctl enabled, we mask it
systemctl --system mask falcoctl-artifact-follow.service || true
;;
esac
fi
clear
fi
set -e
@@ -75,16 +101,16 @@ set -e
echo "[POST-INSTALL] Trigger deamon-reload:"
systemctl --system daemon-reload || true
# If needed, try to load/compile the driver through falco-driver-loader
# If needed, try to load/compile the driver through falcoctl
case "$chosen_driver" in
"kmod")
# Only compile for kmod, in this way we use dkms
echo "[POST-INSTALL] Call 'falco-driver-loader --compile module':"
falco-driver-loader --compile module
echo "[POST-INSTALL] Call 'falcoctl driver install for kmod:"
falcoctl driver install --download=false
;;
"bpf")
echo "[POST-INSTALL] Call 'falco-driver-loader bpf':"
falco-driver-loader bpf
"ebpf")
echo "[POST-INSTALL] Call 'falcoctl driver install for ebpf':"
falcoctl driver install
;;
esac
@@ -95,14 +121,14 @@ esac
# systemd_post macro expands to
# if postinst:
# `systemd-update-helper install-system-units <service>`
%systemd_post "falco-$chosen_driver.service"
%systemd_post "falco-$chosen_unit.service"
# post install/upgrade mirrored from .deb
if [ $1 -ge 1 ]; then
if [ -n "$chosen_driver" ]; then
echo "[POST-INSTALL] Enable 'falco-$chosen_driver.service':"
systemctl --system enable "falco-$chosen_driver.service" || true
echo "[POST-INSTALL] Start 'falco-$chosen_driver.service':"
systemctl --system start "falco-$chosen_driver.service" || true
if [ -n "$chosen_unit" ]; then
echo "[POST-INSTALL] Enable 'falco-$chosen_unit.service':"
systemctl --system enable "falco-$chosen_unit.service" || true
echo "[POST-INSTALL] Start 'falco-$chosen_unit.service':"
systemctl --system start "falco-$chosen_unit.service" || true
fi
fi

View File

@@ -25,8 +25,8 @@ systemctl --system stop 'falco-modern-bpf.service' || true
systemctl --system stop 'falco-custom.service' || true
systemctl --system stop 'falcoctl-artifact-follow.service' || true
echo "[PRE-REMOVE] Call 'falco-driver-loader --clean:'"
falco-driver-loader --clean
echo "[PRE-REMOVE] Call 'falcoctl driver cleanup:'"
falcoctl driver cleanup
# validate rpm macros by `rpm -qp --scripts <rpm>`
# RPM scriptlets: https://docs.fedoraproject.org/en-US/packaging-guidelines/Scriptlets/#_systemd

View File

@@ -7,8 +7,7 @@ Wants=falcoctl-artifact-follow.service
[Service]
Type=simple
User=root
Environment=FALCO_BPF_PROBE=
ExecStart=/usr/bin/falco
ExecStart=/usr/bin/falco -o engine.kind=ebpf
ExecReload=kill -1 $MAINPID
UMask=0077
TimeoutSec=30

View File

@@ -9,7 +9,7 @@ Wants=falcoctl-artifact-follow.service
[Service]
Type=simple
User=root
ExecStart=/usr/bin/falco
ExecStart=/usr/bin/falco -o engine.kind=kmod
ExecReload=kill -1 $MAINPID
UMask=0077
TimeoutSec=30

View File

@@ -7,7 +7,7 @@ Wants=falcoctl-artifact-follow.service
[Service]
Type=simple
User=root
ExecStart=/usr/bin/falco --modern-bpf
ExecStart=/usr/bin/falco -o engine.kind=modern_ebpf
ExecReload=kill -1 $MAINPID
UMask=0077
TimeoutSec=30

View File

@@ -0,0 +1,44 @@
# MIT License
#
# Copyright (c) 2022 raptor
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
rules:
- id: raptor-insecure-api-gets
metadata:
author: Marco Ivaldi <raptor@0xdeadbeef.info>
references:
- https://cwe.mitre.org/data/definitions/242
- https://cwe.mitre.org/data/definitions/120
confidence: HIGH
message: >-
The program calls a function that can never be guaranteed to work
safely.
Certain functions behave in dangerous ways regardless of how they are
used. Functions in this category were often implemented without
taking security concerns into account. The gets() function is unsafe
because it does not perform bounds checking on the size of its input.
An attacker can easily send arbitrarily-sized input to gets() and
overflow the destination buffer.
severity: ERROR
languages:
- c
- cpp
pattern: gets(...)

View File

@@ -0,0 +1,57 @@
# MIT License
#
# Copyright (c) 2022 raptor
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
rules:
- id: raptor-insecure-api-sprintf-vsprintf
metadata:
author: Marco Ivaldi <raptor@0xdeadbeef.info>
references:
- https://cwe.mitre.org/data/definitions/676
- https://cwe.mitre.org/data/definitions/120
- https://cwe.mitre.org/data/definitions/787
- https://g.co/kgs/PCHQjJ
confidence: HIGH
message: >-
The program invokes a potentially dangerous function that could
introduce a vulnerability if it is used incorrectly, but the function
can also be used safely.
A buffer overflow condition exists when a program attempts to put
more data in a buffer than it can hold, or when a program attempts to
put data in a memory area outside of the boundaries of a buffer. The
simplest type of error, and the most common cause of buffer
overflows, is the classic case in which the program copies the buffer
without restricting how much is copied. Other variants exist, but the
existence of a classic overflow strongly suggests that the programmer
is not considering even the most basic of security protections.
severity: ERROR
languages:
- c
- cpp
patterns:
- pattern-either:
- pattern: sprintf($BUF, $FMT, ...)
- pattern: vsprintf($BUF, $FMT, ...)
# swprintf() and vswprintf() should have a size parameter
- metavariable-regex:
metavariable: $FMT
# NOTE: some format string modifiers are not handled
regex: '(".*%l?s.*"|".*%S.*"|[a-zA-Z_][a-zA-Z0-9_]*)'

View File

@@ -0,0 +1,59 @@
# MIT License
#
# Copyright (c) 2022 raptor
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
rules:
- id: raptor-insecure-api-strcpy-stpcpy-strcat
metadata:
author: Marco Ivaldi <raptor@0xdeadbeef.info>
references:
- https://cwe.mitre.org/data/definitions/676
- https://cwe.mitre.org/data/definitions/120
- https://cwe.mitre.org/data/definitions/787
- https://g.co/kgs/PCHQjJ
confidence: HIGH
message: >-
The program invokes a potentially dangerous function that could
introduce a vulnerability if it is used incorrectly, but the function
can also be used safely.
A buffer overflow condition exists when a program attempts to put
more data in a buffer than it can hold, or when a program attempts to
put data in a memory area outside of the boundaries of a buffer. The
simplest type of error, and the most common cause of buffer
overflows, is the classic case in which the program copies the buffer
without restricting how much is copied. Other variants exist, but the
existence of a classic overflow strongly suggests that the programmer
is not considering even the most basic of security protections.
In the Falco codebase you can use the safer alternative strlcpy().
severity: ERROR
languages:
- c
- cpp
patterns:
- pattern-either:
- pattern: strcpy(...)
- pattern: stpcpy(...)
- pattern: strcat(...)
- pattern: wcscpy(...)
- pattern: wcpcpy(...)
- pattern: wcscat(...)
- pattern-not: $FUN($BUF, "...", ...)

View File

@@ -0,0 +1,18 @@
rules:
- id: falco-insecure-api-strn
metadata:
references:
- https://cwe.mitre.org/data/definitions/120
confidence: HIGH
message: >-
The libc function strncpy and strncat are not used in the Falco codebase as they are error prone.
Read more: https://www.cisa.gov/uscert/bsi/articles/knowledge/coding-practices/strncpy-and-strncat .
In the Falco codebase you can use the safer alternatives strlcpy() and strlcat().
severity: ERROR
languages:
- c
- cpp
patterns:
- pattern-either:
- pattern: strncpy(...)
- pattern: strncat(...)

View File

@@ -27,10 +27,18 @@ FetchContent_MakeAvailable(googletest)
file(GLOB_RECURSE ENGINE_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/engine/*.cpp)
file(GLOB_RECURSE FALCO_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/falco/*.cpp)
# Create a libscap_test_var.h file with some variables used by our tests
# for example the kmod path or the bpf path.
configure_file (
"${CMAKE_CURRENT_SOURCE_DIR}/falco_test_var.h.in"
"${CMAKE_CURRENT_BINARY_DIR}/falco_test_var.h"
)
set(FALCO_UNIT_TESTS_SOURCES
"${ENGINE_TESTS}"
falco/test_configuration.cpp
falco/app/actions/test_select_event_sources.cpp
falco/app/actions/test_load_config.cpp
)
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
@@ -45,6 +53,7 @@ set(FALCO_UNIT_TESTS_INCLUDES
${CMAKE_SOURCE_DIR}/userspace
${CMAKE_BINARY_DIR}/userspace/falco # we need it to include indirectly `config_falco.h` file
${CMAKE_SOURCE_DIR}/userspace/engine # we need it to include indirectly `falco_common.h` file
"${CMAKE_CURRENT_BINARY_DIR}" # we need it to include `falco_test_var.h`
)
set(FALCO_UNIT_TESTS_DEPENDENCIES

View File

@@ -0,0 +1,89 @@
// SPDX-License-Identifier: Apache-2.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 <gtest/gtest.h>
#include <falco_engine.h>
#include <evttype_index_ruleset.h>
static std::string syscall_source_name = "syscall";
// A variant of evttype_index_ruleset_factory that uses a singleton
// for the underlying ruleset. This allows testing of
// ruleset_for_source
namespace
{
class test_ruleset_factory : public evttype_index_ruleset_factory
{
public:
test_ruleset_factory(std::shared_ptr<gen_event_filter_factory> factory):
evttype_index_ruleset_factory(factory)
{
ruleset = evttype_index_ruleset_factory::new_ruleset();
}
virtual ~test_ruleset_factory() = default;
inline std::shared_ptr<filter_ruleset> new_ruleset() override
{
return ruleset;
}
std::shared_ptr<filter_ruleset> ruleset;
};
}; // namespace
TEST(AddSource, basic)
{
falco_engine engine;
sinsp inspector;
sinsp_filter_check_list filterchecks;
auto filter_factory = std::shared_ptr<gen_event_filter_factory>(
new sinsp_filter_factory(&inspector, filterchecks));
auto formatter_factory = std::shared_ptr<gen_event_formatter_factory>(
new sinsp_evt_formatter_factory(&inspector, filterchecks));
test_ruleset_factory *test_factory = new test_ruleset_factory(filter_factory);
auto ruleset_factory = std::shared_ptr<filter_ruleset_factory>(test_factory);
falco_source syscall_source;
syscall_source.name = syscall_source_name;
syscall_source.ruleset = ruleset_factory->new_ruleset();
syscall_source.ruleset_factory = ruleset_factory;
syscall_source.filter_factory = filter_factory;
syscall_source.formatter_factory = formatter_factory;
size_t source_idx = engine.add_source(syscall_source_name,
filter_factory,
formatter_factory,
ruleset_factory);
ASSERT_TRUE(engine.is_source_valid(syscall_source_name));
ASSERT_EQ(engine.filter_factory_for_source(syscall_source_name), filter_factory);
ASSERT_EQ(engine.filter_factory_for_source(source_idx), filter_factory);
ASSERT_EQ(engine.formatter_factory_for_source(syscall_source_name), formatter_factory);
ASSERT_EQ(engine.formatter_factory_for_source(source_idx), formatter_factory);
ASSERT_EQ(engine.ruleset_factory_for_source(syscall_source_name), ruleset_factory);
ASSERT_EQ(engine.ruleset_factory_for_source(source_idx), ruleset_factory);
ASSERT_EQ(engine.ruleset_for_source(syscall_source_name), test_factory->ruleset);
ASSERT_EQ(engine.ruleset_for_source(source_idx), test_factory->ruleset);
}

View File

@@ -0,0 +1,251 @@
// SPDX-License-Identifier: Apache-2.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 <string>
#include <gtest/gtest.h>
#include <sinsp.h>
#include <filter_check_list.h>
#include <filter.h>
#include <falco_engine.h>
static std::string single_rule = R"END(
- rule: test rule
desc: A test rule
condition: evt.type=execve
output: A test rule matched (evt.type=%evt.type)
priority: INFO
source: syscall
tags: [process]
- rule: disabled rule
desc: A disabled rule
condition: evt.type=execve
output: A disabled rule matched (evt.type=%evt.type)
priority: INFO
source: syscall
enabled: false
tags: [exec process]
)END";
// This must be kept in line with the (private) falco_engine::s_default_ruleset
static const std::string default_ruleset = "falco-default-ruleset";
static const std::string ruleset_1 = "ruleset-1";
static const std::string ruleset_2 = "ruleset-2";
static const std::string ruleset_3 = "ruleset-3";
static const std::string ruleset_4 = "ruleset-4";
static void load_rules(falco_engine& engine, sinsp& inspector, sinsp_filter_check_list& filterchecks)
{
std::unique_ptr<falco::load_result> res;
auto filter_factory = std::shared_ptr<gen_event_filter_factory>(
new sinsp_filter_factory(&inspector, filterchecks));
auto formatter_factory = std::shared_ptr<gen_event_formatter_factory>(
new sinsp_evt_formatter_factory(&inspector, filterchecks));
engine.add_source("syscall", filter_factory, formatter_factory);
res = engine.load_rules(single_rule, "single_rule.yaml");
EXPECT_TRUE(res->successful());
}
TEST(EnableRule, enable_rule_name)
{
falco_engine engine;
sinsp inspector;
sinsp_filter_check_list filterchecks;
load_rules(engine, inspector, filterchecks);
// No rules should be enabled yet for any custom rulesets
EXPECT_EQ(1, engine.num_rules_for_ruleset(default_ruleset));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_3));
// Enable for first ruleset, only that ruleset should have an
// enabled rule afterward
engine.enable_rule("test", true, ruleset_1);
EXPECT_EQ(1, engine.num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_3));
// Enable for second ruleset
engine.enable_rule("test", true, ruleset_2);
EXPECT_EQ(1, engine.num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(1, engine.num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_3));
// When the substring is blank, all rules are enabled
// (including the disabled rule)
engine.enable_rule("", true, ruleset_3);
EXPECT_EQ(1, engine.num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(1, engine.num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(2, engine.num_rules_for_ruleset(ruleset_3));
// Now disable for second ruleset
engine.enable_rule("test", false, ruleset_2);
EXPECT_EQ(1, engine.num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(2, engine.num_rules_for_ruleset(ruleset_3));
}
TEST(EnableRule, enable_rule_tags)
{
falco_engine engine;
sinsp inspector;
sinsp_filter_check_list filterchecks;
std::set<std::string> process_tags = {"process"};
load_rules(engine, inspector, filterchecks);
// No rules should be enabled yet for any custom rulesets
EXPECT_EQ(1, engine.num_rules_for_ruleset(default_ruleset));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_2));
// Enable for first ruleset, only that ruleset should have an
// enabled rule afterward
engine.enable_rule_by_tag(process_tags, true, ruleset_1);
EXPECT_EQ(1, engine.num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_2));
// Enable for second ruleset
engine.enable_rule_by_tag(process_tags, true, ruleset_2);
EXPECT_EQ(1, engine.num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(1, engine.num_rules_for_ruleset(ruleset_2));
// Now disable for second ruleset
engine.enable_rule_by_tag(process_tags, false, ruleset_2);
EXPECT_EQ(1, engine.num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_2));
}
TEST(EnableRule, enable_disabled_rule_by_tag)
{
falco_engine engine;
sinsp inspector;
sinsp_filter_check_list filterchecks;
std::set<std::string> exec_process_tags = {"exec process"};
load_rules(engine, inspector, filterchecks);
// Only the first rule should be enabled
EXPECT_EQ(1, engine.num_rules_for_ruleset(default_ruleset));
// Enable the disabled rule by tag
engine.enable_rule_by_tag(exec_process_tags, true);
// Both rules should be enabled now
EXPECT_EQ(2, engine.num_rules_for_ruleset(default_ruleset));
}
TEST(EnableRule, enable_rule_id)
{
falco_engine engine;
sinsp inspector;
sinsp_filter_check_list filterchecks;
uint16_t ruleset_1_id;
uint16_t ruleset_2_id;
uint16_t ruleset_3_id;
load_rules(engine, inspector, filterchecks);
// The cases are identical to above, just using ruleset ids
// instead of names.
ruleset_1_id = engine.find_ruleset_id(ruleset_1);
ruleset_2_id = engine.find_ruleset_id(ruleset_2);
ruleset_3_id = engine.find_ruleset_id(ruleset_3);
EXPECT_EQ(1, engine.num_rules_for_ruleset(default_ruleset));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_3));
engine.enable_rule("test rule", true, ruleset_1_id);
EXPECT_EQ(1, engine.num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_3));
engine.enable_rule("test rule", true, ruleset_2_id);
EXPECT_EQ(1, engine.num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(1, engine.num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_3));
engine.enable_rule("", true, ruleset_3_id);
EXPECT_EQ(1, engine.num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(1, engine.num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(2, engine.num_rules_for_ruleset(ruleset_3));
engine.enable_rule("test", false, ruleset_2_id);
EXPECT_EQ(1, engine.num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(2, engine.num_rules_for_ruleset(ruleset_3));
}
TEST(EnableRule, enable_rule_name_exact)
{
falco_engine engine;
sinsp inspector;
sinsp_filter_check_list filterchecks;
load_rules(engine, inspector, filterchecks);
EXPECT_EQ(1, engine.num_rules_for_ruleset(default_ruleset));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_3));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_4));
engine.enable_rule_exact("test rule", true, ruleset_1);
EXPECT_EQ(1, engine.num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_3));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_4));
engine.enable_rule_exact("test rule", true, ruleset_2);
EXPECT_EQ(1, engine.num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(1, engine.num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_3));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_4));
// This should **not** enable as this is a substring and not
// an exact match.
engine.enable_rule_exact("test", true, ruleset_3);
EXPECT_EQ(1, engine.num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(1, engine.num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_3));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_4));
engine.enable_rule_exact("", true, ruleset_4);
EXPECT_EQ(1, engine.num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(1, engine.num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_3));
EXPECT_EQ(2, engine.num_rules_for_ruleset(ruleset_4));
engine.enable_rule("test rule", false, ruleset_2);
EXPECT_EQ(1, engine.num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, engine.num_rules_for_ruleset(ruleset_3));
EXPECT_EQ(2, engine.num_rules_for_ruleset(ruleset_4));
}

View File

@@ -37,17 +37,17 @@ TEST(MacroResolver, should_resolve_macros_on_a_filter_AST)
{
libsinsp::filter::ast::pos_info macro_pos(12, 85, 27);
std::shared_ptr<libsinsp::filter::ast::expr> macro = std::move(libsinsp::filter::ast::unary_check_expr::create("test.field", "", "exists"));
std::shared_ptr<libsinsp::filter::ast::expr> macro = libsinsp::filter::ast::unary_check_expr::create("test.field", "", "exists");
std::vector<std::unique_ptr<libsinsp::filter::ast::expr>> filter_and;
filter_and.push_back(libsinsp::filter::ast::unary_check_expr::create("evt.name", "", "exists"));
filter_and.push_back(libsinsp::filter::ast::not_expr::create(libsinsp::filter::ast::value_expr::create(MACRO_NAME, macro_pos)));
std::shared_ptr<libsinsp::filter::ast::expr> filter = std::move(libsinsp::filter::ast::and_expr::create(filter_and));
std::shared_ptr<libsinsp::filter::ast::expr> filter = libsinsp::filter::ast::and_expr::create(filter_and);
std::vector<std::unique_ptr<libsinsp::filter::ast::expr>> expected_and;
expected_and.push_back(libsinsp::filter::ast::unary_check_expr::create("evt.name", "", "exists"));
expected_and.push_back(libsinsp::filter::ast::not_expr::create(clone(macro.get())));
std::shared_ptr<libsinsp::filter::ast::expr> expected = std::move(libsinsp::filter::ast::and_expr::create(expected_and));
std::shared_ptr<libsinsp::filter::ast::expr> expected = libsinsp::filter::ast::and_expr::create(expected_and);
filter_macro_resolver resolver;
resolver.set_macro(MACRO_NAME, macro);
@@ -71,9 +71,9 @@ TEST(MacroResolver, should_resolve_macros_on_a_filter_AST_single_node)
{
libsinsp::filter::ast::pos_info macro_pos(12, 85, 27);
std::shared_ptr<libsinsp::filter::ast::expr> macro = std::move(libsinsp::filter::ast::unary_check_expr::create("test.field", "", "exists"));
std::shared_ptr<libsinsp::filter::ast::expr> macro = libsinsp::filter::ast::unary_check_expr::create("test.field", "", "exists");
std::shared_ptr<libsinsp::filter::ast::expr> filter = std::move(libsinsp::filter::ast::value_expr::create(MACRO_NAME, macro_pos));
std::shared_ptr<libsinsp::filter::ast::expr> filter = libsinsp::filter::ast::value_expr::create(MACRO_NAME, macro_pos);
filter_macro_resolver resolver;
resolver.set_macro(MACRO_NAME, macro);
@@ -102,18 +102,18 @@ TEST(MacroResolver, should_resolve_macros_on_a_filter_AST_multiple_macros)
libsinsp::filter::ast::pos_info a_macro_pos(11, 75, 43);
libsinsp::filter::ast::pos_info b_macro_pos(91, 21, 9);
std::shared_ptr<libsinsp::filter::ast::expr> a_macro = std::move(libsinsp::filter::ast::unary_check_expr::create("one.field", "", "exists"));
std::shared_ptr<libsinsp::filter::ast::expr> b_macro = std::move(libsinsp::filter::ast::unary_check_expr::create("another.field", "", "exists"));
std::shared_ptr<libsinsp::filter::ast::expr> a_macro = libsinsp::filter::ast::unary_check_expr::create("one.field", "", "exists");
std::shared_ptr<libsinsp::filter::ast::expr> b_macro = libsinsp::filter::ast::unary_check_expr::create("another.field", "", "exists");
std::vector<std::unique_ptr<libsinsp::filter::ast::expr>> filter_or;
filter_or.push_back(libsinsp::filter::ast::value_expr::create(MACRO_A_NAME, a_macro_pos));
filter_or.push_back(libsinsp::filter::ast::value_expr::create(MACRO_B_NAME, b_macro_pos));
std::shared_ptr<libsinsp::filter::ast::expr> filter = std::move(libsinsp::filter::ast::or_expr::create(filter_or));
std::shared_ptr<libsinsp::filter::ast::expr> filter = libsinsp::filter::ast::or_expr::create(filter_or);
std::vector<std::unique_ptr<libsinsp::filter::ast::expr>> expected_or;
expected_or.push_back(clone(a_macro.get()));
expected_or.push_back(clone(b_macro.get()));
std::shared_ptr<libsinsp::filter::ast::expr> expected_filter = std::move(libsinsp::filter::ast::or_expr::create(expected_or));
std::shared_ptr<libsinsp::filter::ast::expr> expected_filter = libsinsp::filter::ast::or_expr::create(expected_or);
filter_macro_resolver resolver;
resolver.set_macro(MACRO_A_NAME, a_macro);
@@ -149,17 +149,17 @@ TEST(MacroResolver, should_resolve_macros_on_a_filter_AST_nested_macros)
std::vector<std::unique_ptr<libsinsp::filter::ast::expr>> a_macro_and;
a_macro_and.push_back(libsinsp::filter::ast::unary_check_expr::create("one.field", "", "exists"));
a_macro_and.push_back(libsinsp::filter::ast::value_expr::create(MACRO_B_NAME, b_macro_pos));
std::shared_ptr<libsinsp::filter::ast::expr> a_macro = std::move(libsinsp::filter::ast::and_expr::create(a_macro_and));
std::shared_ptr<libsinsp::filter::ast::expr> a_macro = libsinsp::filter::ast::and_expr::create(a_macro_and);
std::shared_ptr<libsinsp::filter::ast::expr> b_macro = std::move(
libsinsp::filter::ast::unary_check_expr::create("another.field", "", "exists"));
std::shared_ptr<libsinsp::filter::ast::expr> b_macro =
libsinsp::filter::ast::unary_check_expr::create("another.field", "", "exists");
std::shared_ptr<libsinsp::filter::ast::expr> filter = std::move(libsinsp::filter::ast::value_expr::create(MACRO_A_NAME, a_macro_pos));
std::shared_ptr<libsinsp::filter::ast::expr> filter = libsinsp::filter::ast::value_expr::create(MACRO_A_NAME, a_macro_pos);
std::vector<std::unique_ptr<libsinsp::filter::ast::expr>> expected_and;
expected_and.push_back(libsinsp::filter::ast::unary_check_expr::create("one.field", "", "exists"));
expected_and.push_back(libsinsp::filter::ast::unary_check_expr::create("another.field", "", "exists"));
std::shared_ptr<libsinsp::filter::ast::expr> expected_filter = std::move(libsinsp::filter::ast::and_expr::create(expected_and));
std::shared_ptr<libsinsp::filter::ast::expr> expected_filter = libsinsp::filter::ast::and_expr::create(expected_and);
filter_macro_resolver resolver;
resolver.set_macro(MACRO_A_NAME, a_macro);
@@ -196,7 +196,7 @@ TEST(MacroResolver, should_find_unknown_macros)
std::vector<std::unique_ptr<libsinsp::filter::ast::expr>> filter_and;
filter_and.push_back(libsinsp::filter::ast::unary_check_expr::create("evt.name", "", "exists"));
filter_and.push_back(libsinsp::filter::ast::not_expr::create(libsinsp::filter::ast::value_expr::create(MACRO_NAME, macro_pos)));
std::shared_ptr<libsinsp::filter::ast::expr> filter = std::move(libsinsp::filter::ast::and_expr::create(filter_and));
std::shared_ptr<libsinsp::filter::ast::expr> filter = libsinsp::filter::ast::and_expr::create(filter_and);
filter_macro_resolver resolver;
ASSERT_FALSE(resolver.run(filter));
@@ -214,9 +214,9 @@ TEST(MacroResolver, should_find_unknown_nested_macros)
std::vector<std::unique_ptr<libsinsp::filter::ast::expr>> a_macro_and;
a_macro_and.push_back(libsinsp::filter::ast::unary_check_expr::create("one.field", "", "exists"));
a_macro_and.push_back(libsinsp::filter::ast::value_expr::create(MACRO_B_NAME, b_macro_pos));
std::shared_ptr<libsinsp::filter::ast::expr> a_macro = std::move(libsinsp::filter::ast::and_expr::create(a_macro_and));
std::shared_ptr<libsinsp::filter::ast::expr> a_macro = libsinsp::filter::ast::and_expr::create(a_macro_and);
std::shared_ptr<libsinsp::filter::ast::expr> filter = std::move(libsinsp::filter::ast::value_expr::create(MACRO_A_NAME, a_macro_pos));
std::shared_ptr<libsinsp::filter::ast::expr> filter = libsinsp::filter::ast::value_expr::create(MACRO_A_NAME, a_macro_pos);
auto expected_filter = clone(a_macro.get());
filter_macro_resolver resolver;
@@ -237,9 +237,9 @@ TEST(MacroResolver, should_undefine_macro)
libsinsp::filter::ast::pos_info macro_pos_1(12, 9, 3);
libsinsp::filter::ast::pos_info macro_pos_2(9, 6, 3);
std::shared_ptr<libsinsp::filter::ast::expr> macro = std::move(libsinsp::filter::ast::unary_check_expr::create("test.field", "", "exists"));
std::shared_ptr<libsinsp::filter::ast::expr> a_filter = std::move(libsinsp::filter::ast::value_expr::create(MACRO_NAME, macro_pos_1));
std::shared_ptr<libsinsp::filter::ast::expr> b_filter = std::move(libsinsp::filter::ast::value_expr::create(MACRO_NAME, macro_pos_2));
std::shared_ptr<libsinsp::filter::ast::expr> macro = libsinsp::filter::ast::unary_check_expr::create("test.field", "", "exists");
std::shared_ptr<libsinsp::filter::ast::expr> a_filter = libsinsp::filter::ast::value_expr::create(MACRO_NAME, macro_pos_1);
std::shared_ptr<libsinsp::filter::ast::expr> b_filter = libsinsp::filter::ast::value_expr::create(MACRO_NAME, macro_pos_2);
filter_macro_resolver resolver;
resolver.set_macro(MACRO_NAME, macro);
@@ -262,8 +262,8 @@ TEST(MacroResolver, should_undefine_macro)
TEST(MacroResolver, should_clone_macro_AST)
{
libsinsp::filter::ast::pos_info macro_pos(5, 2, 8888);
std::shared_ptr<libsinsp::filter::ast::unary_check_expr> macro = std::move(libsinsp::filter::ast::unary_check_expr::create("test.field", "", "exists"));
std::shared_ptr<libsinsp::filter::ast::expr> filter = std::move(libsinsp::filter::ast::value_expr::create(MACRO_NAME, macro_pos));
std::shared_ptr<libsinsp::filter::ast::unary_check_expr> macro = libsinsp::filter::ast::unary_check_expr::create("test.field", "", "exists");
std::shared_ptr<libsinsp::filter::ast::expr> filter = libsinsp::filter::ast::value_expr::create(MACRO_NAME, macro_pos);
filter_macro_resolver resolver;
resolver.set_macro(MACRO_NAME, macro);

View File

@@ -0,0 +1,970 @@
#include <gtest/gtest.h>
#include "falco_engine.h"
#include "rule_loader_reader.h"
#include "rule_loader_compiler.h"
#include "rule_loading_messages.h"
class engine_loader_test : public ::testing::Test {
protected:
void SetUp() override
{
m_sample_ruleset = "sample-ruleset";
m_sample_source = falco_common::syscall_source;
// create a falco engine ready to load the ruleset
m_inspector.reset(new sinsp());
m_engine.reset(new falco_engine());
m_filter_factory = std::shared_ptr<gen_event_filter_factory>(
new sinsp_filter_factory(m_inspector.get(), m_filterlist));
m_formatter_factory = std::shared_ptr<gen_event_formatter_factory>(
new sinsp_evt_formatter_factory(m_inspector.get(), m_filterlist));
m_engine->add_source(m_sample_source, m_filter_factory, m_formatter_factory);
}
void TearDown() override
{
}
bool load_rules(std::string rules_content, std::string rules_filename)
{
bool ret = false;
falco::load_result::rules_contents_t rc = {{rules_filename, rules_content}};
m_load_result = m_engine->load_rules(rules_content, rules_filename);
m_load_result_string = m_load_result->as_string(true, rc);
m_load_result_json = m_load_result->as_json(rc);
ret = m_load_result->successful();
if (ret)
{
m_engine->enable_rule("", true, m_sample_ruleset);
}
return ret;
}
// This must be kept in line with the (private) falco_engine::s_default_ruleset
uint64_t num_rules_for_ruleset(std::string ruleset = "falco-default-ruleset")
{
return m_engine->num_rules_for_ruleset(ruleset);
}
bool has_warnings()
{
return m_load_result->has_warnings();
}
bool check_warning_message(std::string warning_msg)
{
if(!m_load_result->has_warnings())
{
return false;
}
for(auto &warn : m_load_result_json["warnings"])
{
std::string msg = warn["message"];
// Debug:
// printf("msg: %s\n", msg.c_str());
if(msg.find(warning_msg) != std::string::npos)
{
return true;
}
}
return false;
}
bool check_error_message(std::string error_msg)
{
// if the loading is successful there are no errors
if(m_load_result->successful())
{
return false;
}
for(auto &err : m_load_result_json["errors"])
{
std::string msg = err["message"];
// Debug:
// printf("msg: %s\n", msg.c_str());
if(msg.find(error_msg) != std::string::npos)
{
return true;
}
}
return false;
}
std::string get_compiled_rule_condition(std::string rule_name = "")
{
auto rule_description = m_engine->describe_rule(&rule_name, {});
return rule_description["rules"][0]["details"]["condition_compiled"].template get<std::string>();
}
std::string m_sample_ruleset;
std::string m_sample_source;
sinsp_filter_check_list m_filterlist;
std::shared_ptr<gen_event_filter_factory> m_filter_factory;
std::shared_ptr<gen_event_formatter_factory> m_formatter_factory;
std::unique_ptr<falco_engine> m_engine;
std::unique_ptr<falco::load_result> m_load_result;
std::string m_load_result_string;
nlohmann::json m_load_result_json;
std::unique_ptr<sinsp> m_inspector;
};
std::string s_sample_ruleset = "sample-ruleset";
std::string s_sample_source = falco_common::syscall_source;
TEST_F(engine_loader_test, list_append)
{
std::string rules_content = R"END(
- list: shell_binaries
items: [ash, bash, csh, ksh, sh, tcsh, zsh, dash]
- rule: legit_rule
desc: legit rule description
condition: evt.type=open and proc.name in (shell_binaries)
output: user=%user.name command=%proc.cmdline file=%fd.name
priority: INFO
- list: shell_binaries
items: [pwsh]
override:
items: append
)END";
ASSERT_TRUE(load_rules(rules_content, "legit_rules.yaml")) << m_load_result_string;
ASSERT_EQ(get_compiled_rule_condition("legit_rule"),"(evt.type = open and proc.name in (ash, bash, csh, ksh, sh, tcsh, zsh, dash, pwsh))");
}
TEST_F(engine_loader_test, condition_append)
{
std::string rules_content = R"END(
- macro: interactive
condition: >
((proc.aname=sshd and proc.name != sshd) or
proc.name=systemd-logind or proc.name=login)
- rule: legit_rule
desc: legit rule description
condition: evt.type=open and interactive
output: user=%user.name command=%proc.cmdline file=%fd.name
priority: INFO
- macro: interactive
condition: or proc.name = ssh
override:
condition: append
)END";
ASSERT_TRUE(load_rules(rules_content, "legit_rules.yaml")) << m_load_result_string;
ASSERT_EQ(get_compiled_rule_condition("legit_rule"),"(evt.type = open and (((proc.aname = sshd and proc.name != sshd) or proc.name = systemd-logind or proc.name = login) or proc.name = ssh))");
}
TEST_F(engine_loader_test, rule_override_append)
{
std::string rules_content = R"END(
- rule: legit_rule
desc: legit rule description
condition: evt.type=open
output: user=%user.name command=%proc.cmdline file=%fd.name
priority: INFO
- rule: legit_rule
desc: with append
condition: and proc.name = cat
output: proc=%proc.name
override:
desc: append
condition: append
output: append
)END";
std::string rule_name = "legit_rule";
ASSERT_TRUE(load_rules(rules_content, "legit_rules.yaml")) << m_load_result_string;
// Here we don't use the deprecated `append` flag, so we don't expect the warning.
ASSERT_FALSE(check_warning_message(WARNING_APPEND));
auto rule_description = m_engine->describe_rule(&rule_name, {});
ASSERT_EQ(rule_description["rules"][0]["info"]["condition"].template get<std::string>(),
"evt.type=open and proc.name = cat");
ASSERT_EQ(rule_description["rules"][0]["info"]["output"].template get<std::string>(),
"user=%user.name command=%proc.cmdline file=%fd.name proc=%proc.name");
ASSERT_EQ(rule_description["rules"][0]["info"]["description"].template get<std::string>(),
"legit rule description with append");
}
TEST_F(engine_loader_test, rule_append)
{
std::string rules_content = R"END(
- rule: legit_rule
desc: legit rule description
condition: evt.type=open
output: user=%user.name command=%proc.cmdline file=%fd.name
priority: INFO
- rule: legit_rule
condition: and proc.name = cat
append: true
)END";
ASSERT_TRUE(load_rules(rules_content, "legit_rules.yaml")) << m_load_result_string;
// We should have at least one warning because the 'append' flag is deprecated.
ASSERT_TRUE(check_warning_message(WARNING_APPEND));
ASSERT_EQ(get_compiled_rule_condition("legit_rule"),"(evt.type = open and proc.name = cat)");
}
TEST_F(engine_loader_test, rule_override_replace)
{
std::string rules_content = R"END(
- rule: legit_rule
desc: legit rule description
condition: evt.type=open
output: user=%user.name command=%proc.cmdline file=%fd.name
priority: INFO
- rule: legit_rule
desc: a replaced legit description
condition: evt.type = close
override:
desc: replace
condition: replace
)END";
std::string rule_name = "legit_rule";
ASSERT_TRUE(load_rules(rules_content, "legit_rules.yaml")) << m_load_result_string;
auto rule_description = m_engine->describe_rule(&rule_name, {});
ASSERT_EQ(rule_description["rules"][0]["info"]["condition"].template get<std::string>(),
"evt.type = close");
ASSERT_EQ(rule_description["rules"][0]["info"]["output"].template get<std::string>(),
"user=%user.name command=%proc.cmdline file=%fd.name");
ASSERT_EQ(rule_description["rules"][0]["info"]["description"].template get<std::string>(),
"a replaced legit description");
}
TEST_F(engine_loader_test, rule_override_append_replace)
{
std::string rules_content = R"END(
- rule: legit_rule
desc: legit rule description
condition: evt.type = close
output: user=%user.name command=%proc.cmdline file=%fd.name
priority: INFO
- rule: legit_rule
desc: a replaced legit description
condition: and proc.name = cat
priority: WARNING
override:
desc: replace
condition: append
priority: replace
)END";
std::string rule_name = "legit_rule";
ASSERT_TRUE(load_rules(rules_content, "legit_rules.yaml")) << m_load_result_string;
auto rule_description = m_engine->describe_rule(&rule_name, {});
ASSERT_EQ(rule_description["rules"][0]["info"]["condition"].template get<std::string>(),
"evt.type = close and proc.name = cat");
ASSERT_EQ(rule_description["rules"][0]["info"]["output"].template get<std::string>(),
"user=%user.name command=%proc.cmdline file=%fd.name");
ASSERT_EQ(rule_description["rules"][0]["info"]["description"].template get<std::string>(),
"a replaced legit description");
ASSERT_EQ(rule_description["rules"][0]["info"]["priority"].template get<std::string>(),
"Warning");
}
TEST_F(engine_loader_test, rule_incorrect_override_type)
{
std::string rules_content = R"END(
- rule: failing_rule
desc: legit rule description
condition: evt.type = close
output: user=%user.name command=%proc.cmdline file=%fd.name
priority: INFO
- rule: failing_rule
desc: an appended incorrect field
condition: and proc.name = cat
priority: WARNING
override:
desc: replace
condition: append
priority: append
)END";
std::string rule_name = "failing_rule";
ASSERT_FALSE(load_rules(rules_content, "rules.yaml"));
ASSERT_TRUE(check_error_message("Key 'priority' cannot be appended to, use 'replace' instead"));
ASSERT_TRUE(std::string(m_load_result_json["errors"][0]["context"]["snippet"]).find("priority: append") != std::string::npos);
}
TEST_F(engine_loader_test, rule_incorrect_append_override)
{
std::string rules_content = R"END(
- rule: failing_rule
desc: legit rule description
condition: evt.type = close
output: user=%user.name command=%proc.cmdline file=%fd.name
priority: INFO
- rule: failing_rule
desc: an appended incorrect field
condition: and proc.name = cat
append: true
override:
desc: replace
condition: append
)END";
std::string rule_name = "failing_rule";
ASSERT_FALSE(load_rules(rules_content, "rules.yaml"));
// We should have at least one warning because the 'append' flag is deprecated.
ASSERT_TRUE(check_warning_message(WARNING_APPEND));
ASSERT_TRUE(check_error_message(ERROR_OVERRIDE_APPEND));
}
TEST_F(engine_loader_test, macro_override_append_before_macro_definition)
{
std::string rules_content = R"END(
- macro: open_simple
condition: or evt.type = openat2
override:
condition: append
- macro: open_simple
condition: evt.type in (open,openat)
- rule: test_rule
desc: simple rule
condition: open_simple
output: command=%proc.cmdline
priority: INFO
)END";
// We cannot define a macro override before the macro definition.
ASSERT_FALSE(load_rules(rules_content, "rules.yaml"));
ASSERT_TRUE(check_error_message(ERROR_NO_PREVIOUS_MACRO));
}
TEST_F(engine_loader_test, macro_override_replace_before_macro_definition)
{
std::string rules_content = R"END(
- macro: open_simple
condition: or evt.type = openat2
override:
condition: replace
- macro: open_simple
condition: evt.type in (open,openat)
- rule: test_rule
desc: simple rule
condition: open_simple
output: command=%proc.cmdline
priority: INFO
)END";
// The first override defines a macro that is overridden by the second macro definition
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
ASSERT_EQ(get_compiled_rule_condition("test_rule"),"evt.type in (open, openat)");
}
TEST_F(engine_loader_test, macro_append_before_macro_definition)
{
std::string rules_content = R"END(
- macro: open_simple
condition: or evt.type = openat2
append: true
- macro: open_simple
condition: evt.type in (open,openat)
- rule: test_rule
desc: simple rule
condition: open_simple
output: command=%proc.cmdline
priority: INFO
)END";
// We cannot define a macro override before the macro definition.
ASSERT_FALSE(load_rules(rules_content, "rules.yaml"));
ASSERT_TRUE(check_error_message(ERROR_NO_PREVIOUS_MACRO));
}
TEST_F(engine_loader_test, macro_override_append_after_macro_definition)
{
std::string rules_content = R"END(
- macro: open_simple
condition: evt.type in (open,openat)
- macro: open_simple
condition: or evt.type = openat2
override:
condition: append
- rule: test_rule
desc: simple rule
condition: open_simple
output: command=%proc.cmdline
priority: INFO
)END";
// We cannot define a macro override before the macro definition.
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
ASSERT_EQ(get_compiled_rule_condition("test_rule"),"(evt.type in (open, openat) or evt.type = openat2)");
}
TEST_F(engine_loader_test, macro_append_after_macro_definition)
{
std::string rules_content = R"END(
- macro: open_simple
condition: evt.type in (open,openat)
- macro: open_simple
condition: or evt.type = openat2
append: true
- rule: test_rule
desc: simple rule
condition: open_simple
output: command=%proc.cmdline
priority: INFO
)END";
// We cannot define a macro override before the macro definition.
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
ASSERT_EQ(get_compiled_rule_condition("test_rule"),"(evt.type in (open, openat) or evt.type = openat2)");
}
TEST_F(engine_loader_test, rule_override_append_before_rule_definition)
{
std::string rules_content = R"END(
- rule: test_rule
condition: and proc.name = cat
override:
condition: append
- rule: test_rule
desc: simple rule
condition: evt.type in (open,openat)
output: command=%proc.cmdline
priority: INFO
)END";
ASSERT_FALSE(load_rules(rules_content, "rules.yaml"));
ASSERT_TRUE(check_error_message(ERROR_NO_PREVIOUS_RULE_APPEND));
}
TEST_F(engine_loader_test, rule_override_replace_before_rule_definition)
{
std::string rules_content = R"END(
- rule: test_rule
condition: and proc.name = cat
override:
condition: replace
- rule: test_rule
desc: simple rule
condition: evt.type in (open,openat)
output: command=%proc.cmdline
priority: INFO
)END";
ASSERT_FALSE(load_rules(rules_content, "rules.yaml"));
ASSERT_TRUE(check_error_message(ERROR_NO_PREVIOUS_RULE_REPLACE));
}
TEST_F(engine_loader_test, rule_append_before_rule_definition)
{
std::string rules_content = R"END(
- rule: test_rule
condition: and proc.name = cat
append: true
- rule: test_rule
desc: simple rule
condition: evt.type in (open,openat)
output: command=%proc.cmdline
priority: INFO
)END";
ASSERT_FALSE(load_rules(rules_content, "rules.yaml"));
ASSERT_TRUE(check_error_message(ERROR_NO_PREVIOUS_RULE_APPEND));
}
TEST_F(engine_loader_test, rule_override_append_after_rule_definition)
{
std::string rules_content = R"END(
- rule: test_rule
desc: simple rule
condition: evt.type in (open,openat)
output: command=%proc.cmdline
priority: INFO
- rule: test_rule
condition: and proc.name = cat
override:
condition: append
)END";
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
ASSERT_EQ(get_compiled_rule_condition("test_rule"),"(evt.type in (open, openat) and proc.name = cat)");
}
TEST_F(engine_loader_test, rule_append_after_rule_definition)
{
std::string rules_content = R"END(
- rule: test_rule
desc: simple rule
condition: evt.type in (open,openat)
output: command=%proc.cmdline
priority: INFO
- rule: test_rule
condition: and proc.name = cat
append: true
)END";
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
ASSERT_EQ(get_compiled_rule_condition("test_rule"),"(evt.type in (open, openat) and proc.name = cat)");
}
TEST_F(engine_loader_test, list_override_append_wrong_key)
{
// todo: maybe we want to manage some non-existent keys
// Please note how the non-existent key 'non-existent keys' is ignored.
std::string rules_content = R"END(
- list: dev_creation_binaries
items: ["csi-provisioner", "csi-attacher"]
override_written_wrong:
items: append
- list: dev_creation_binaries
items: [blkid]
- rule: test_rule
desc: simple rule
condition: evt.type = execve and proc.name in (dev_creation_binaries)
output: command=%proc.cmdline
priority: INFO
)END";
// Since there is a wrong key in the first list definition the `override` is not
// considered. so in this situation, we are defining the list 2 times. The
// second one overrides the first one.
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
ASSERT_EQ(get_compiled_rule_condition("test_rule"),"(evt.type = execve and proc.name in (blkid))");
}
TEST_F(engine_loader_test, list_override_append_before_list_definition)
{
std::string rules_content = R"END(
- list: dev_creation_binaries
items: ["csi-provisioner", "csi-attacher"]
override:
items: append
- list: dev_creation_binaries
items: [blkid]
- rule: test_rule
desc: simple rule
condition: evt.type = execve and proc.name in (dev_creation_binaries)
output: command=%proc.cmdline
priority: INFO
)END";
// We cannot define a list override before the list definition.
ASSERT_FALSE(load_rules(rules_content, "rules.yaml"));
ASSERT_TRUE(check_error_message(ERROR_NO_PREVIOUS_LIST));
}
TEST_F(engine_loader_test, list_override_replace_before_list_definition)
{
std::string rules_content = R"END(
- list: dev_creation_binaries
items: ["csi-provisioner", "csi-attacher"]
override:
items: replace
- list: dev_creation_binaries
items: [blkid]
- rule: test_rule
desc: simple rule
condition: evt.type = execve and proc.name in (dev_creation_binaries)
output: command=%proc.cmdline
priority: INFO
)END";
// With override replace we define a first list that then is overridden by the second one.
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
ASSERT_EQ(get_compiled_rule_condition("test_rule"),"(evt.type = execve and proc.name in (blkid))");
}
TEST_F(engine_loader_test, list_append_before_list_definition)
{
std::string rules_content = R"END(
- list: dev_creation_binaries
items: ["csi-provisioner", "csi-attacher"]
append: true
- list: dev_creation_binaries
items: [blkid]
- rule: test_rule
desc: simple rule
condition: evt.type = execve and proc.name in (dev_creation_binaries)
output: command=%proc.cmdline
priority: INFO
)END";
// We cannot define a list append before the list definition.
ASSERT_FALSE(load_rules(rules_content, "rules.yaml"));
ASSERT_TRUE(check_error_message(ERROR_NO_PREVIOUS_LIST));
}
TEST_F(engine_loader_test, list_override_append_after_list_definition)
{
std::string rules_content = R"END(
- list: dev_creation_binaries
items: [blkid]
- list: dev_creation_binaries
items: ["csi-provisioner", "csi-attacher"]
override:
items: append
- rule: test_rule
desc: simple rule
condition: evt.type = execve and proc.name in (dev_creation_binaries)
output: command=%proc.cmdline
priority: INFO
)END";
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
ASSERT_EQ(get_compiled_rule_condition("test_rule"),"(evt.type = execve and proc.name in (blkid, csi-provisioner, csi-attacher))");
}
TEST_F(engine_loader_test, list_append_after_list_definition)
{
std::string rules_content = R"END(
- list: dev_creation_binaries
items: [blkid]
- list: dev_creation_binaries
items: ["csi-provisioner", "csi-attacher"]
append: true
- rule: test_rule
desc: simple rule
condition: evt.type = execve and proc.name in (dev_creation_binaries)
output: command=%proc.cmdline
priority: INFO
)END";
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
ASSERT_EQ(get_compiled_rule_condition("test_rule"),"(evt.type = execve and proc.name in (blkid, csi-provisioner, csi-attacher))");
}
TEST_F(engine_loader_test, rule_override_without_field)
{
std::string rules_content = R"END(
- rule: failing_rule
desc: legit rule description
condition: evt.type = close
output: user=%user.name command=%proc.cmdline file=%fd.name
priority: INFO
- rule: failing_rule
desc: an appended incorrect field
override:
desc: replace
condition: append
)END";
std::string rule_name = "failing_rule";
ASSERT_FALSE(load_rules(rules_content, "rules.yaml"));
ASSERT_TRUE(check_error_message("An append override for 'condition' was specified but 'condition' is not defined"));
}
TEST_F(engine_loader_test, rule_override_extra_field)
{
std::string rules_content = R"END(
- rule: failing_rule
desc: legit rule description
condition: evt.type = close
output: user=%user.name command=%proc.cmdline file=%fd.name
priority: INFO
- rule: failing_rule
desc: an appended incorrect field
condition: and proc.name = cat
priority: WARNING
override:
desc: replace
condition: append
)END";
std::string rule_name = "failing_rule";
ASSERT_FALSE(load_rules(rules_content, "rules.yaml"));
ASSERT_TRUE(check_error_message("Unexpected key 'priority'"));
}
TEST_F(engine_loader_test, missing_enabled_key_with_override)
{
std::string rules_content = R"END(
- rule: test_rule
desc: test rule description
condition: evt.type = close
output: user=%user.name command=%proc.cmdline file=%fd.name
priority: INFO
enabled: false
- rule: test_rule
desc: missing enabled key
condition: and proc.name = cat
override:
desc: replace
condition: append
enabled: replace
)END";
// In the rule override we miss `enabled: true`
ASSERT_FALSE(load_rules(rules_content, "rules.yaml"));
ASSERT_TRUE(check_error_message("'enabled' was specified but 'enabled' is not defined"));
}
TEST_F(engine_loader_test, rule_override_with_enabled)
{
std::string rules_content = R"END(
- rule: test_rule
desc: test rule description
condition: evt.type = close
output: user=%user.name command=%proc.cmdline file=%fd.name
priority: INFO
enabled: false
- rule: test_rule
desc: correct override
condition: and proc.name = cat
enabled: true
override:
desc: replace
condition: append
enabled: replace
)END";
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
ASSERT_FALSE(has_warnings());
// The rule should be enabled at the end.
EXPECT_EQ(num_rules_for_ruleset(), 1);
}
TEST_F(engine_loader_test, rule_not_enabled)
{
std::string rules_content = R"END(
- rule: test_rule
desc: rule not enabled
condition: evt.type = close
output: user=%user.name command=%proc.cmdline file=%fd.name
priority: INFO
enabled: false
)END";
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
ASSERT_FALSE(has_warnings());
EXPECT_EQ(num_rules_for_ruleset(), 0);
}
TEST_F(engine_loader_test, rule_enabled_warning)
{
std::string rules_content = R"END(
- rule: test_rule
desc: test rule description
condition: evt.type = close
output: user=%user.name command=%proc.cmdline file=%fd.name
priority: INFO
enabled: false
- rule: test_rule
enabled: true
)END";
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
ASSERT_TRUE(check_warning_message(WARNING_ENABLED));
// The rule should be enabled at the end.
EXPECT_EQ(num_rules_for_ruleset(), 1);
}
// todo!: Probably we shouldn't allow this syntax
TEST_F(engine_loader_test, rule_enabled_is_ignored_by_append)
{
std::string rules_content = R"END(
- rule: test_rule
desc: test rule description
condition: evt.type = close
output: user=%user.name command=%proc.cmdline file=%fd.name
priority: INFO
enabled: false
- rule: test_rule
condition: and proc.name = cat
append: true
enabled: true
)END";
// 'enabled' is ignored by the append, this syntax is not supported
// so the rule is not enabled.
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
EXPECT_EQ(num_rules_for_ruleset(), 0);
}
// todo!: Probably we shouldn't allow this syntax
TEST_F(engine_loader_test, rewrite_rule)
{
std::string rules_content = R"END(
- rule: test_rule
desc: test rule description
condition: evt.type = close
output: user=%user.name command=%proc.cmdline file=%fd.name
priority: INFO
enabled: false
- rule: test_rule
desc: redefined rule syntax
condition: proc.name = cat
output: user=%user.name command=%proc.cmdline file=%fd.name
priority: WARNING
enabled: true
)END";
// The above syntax is not supported, we cannot override the content
// of a rule in this way.
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
// In this case the rule is completely overridden but this syntax is not supported.
EXPECT_EQ(num_rules_for_ruleset(), 1);
ASSERT_EQ(get_compiled_rule_condition("test_rule"),"proc.name = cat");
}
TEST_F(engine_loader_test, required_engine_version_semver)
{
std::string rules_content = R"END(
- required_engine_version: 0.26.0
- rule: test_rule
desc: test rule description
condition: evt.type = close
output: user=%user.name command=%proc.cmdline file=%fd.name
priority: INFO
enabled: false
)END";
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
ASSERT_FALSE(has_warnings());
}
TEST_F(engine_loader_test, required_engine_version_not_semver)
{
std::string rules_content = R"END(
- required_engine_version: 26
- rule: test_rule
desc: test rule description
condition: evt.type = close
output: user=%user.name command=%proc.cmdline file=%fd.name
priority: INFO
enabled: false
)END";
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
ASSERT_FALSE(has_warnings());
}
TEST_F(engine_loader_test, required_engine_version_invalid)
{
std::string rules_content = R"END(
- required_engine_version: seven
- rule: test_rule
desc: test rule description
condition: evt.type = close
output: user=%user.name command=%proc.cmdline file=%fd.name
priority: INFO
enabled: false
)END";
ASSERT_FALSE(load_rules(rules_content, "rules.yaml"));
ASSERT_TRUE(check_error_message("Unable to parse engine version"));
}
// checks for issue described in https://github.com/falcosecurity/falco/pull/3028
TEST_F(engine_loader_test, list_value_with_escaping)
{
std::string rules_content = R"END(
- list: my_list
items: [non_escaped_val, "escaped val"]
)END";
ASSERT_TRUE(load_rules(rules_content, "rules.yaml"));
ASSERT_TRUE(m_load_result->successful());
ASSERT_TRUE(m_load_result->has_warnings()); // a warning for the unused list
auto rule_description = m_engine->describe_rule(nullptr, {});
ASSERT_TRUE(m_load_result->successful());
ASSERT_EQ(rule_description["rules"].size(), 0);
ASSERT_EQ(rule_description["macros"].size(), 0);
ASSERT_EQ(rule_description["lists"].size(), 1);
// escaped values must not be interpreted as list refs by mistake
ASSERT_EQ(rule_description["lists"][0]["details"]["lists"].size(), 0);
// values should be escaped correctly
ASSERT_EQ(rule_description["lists"][0]["details"]["items_compiled"].size(), 2);
ASSERT_EQ(rule_description["lists"][0]["details"]["items_compiled"][0].template get<std::string>(), "non_escaped_val");
ASSERT_EQ(rule_description["lists"][0]["details"]["items_compiled"][1].template get<std::string>(), "escaped val");
}

View File

@@ -23,9 +23,9 @@ limitations under the License.
#define RULESET_2 2
/* Helpers methods */
static std::shared_ptr<gen_event_filter_factory> create_factory()
static std::shared_ptr<gen_event_filter_factory> create_factory(filter_check_list& list)
{
std::shared_ptr<gen_event_filter_factory> ret(new sinsp_filter_factory(NULL));
std::shared_ptr<gen_event_filter_factory> ret(new sinsp_filter_factory(NULL, list));
return ret;
}
@@ -53,7 +53,8 @@ static std::shared_ptr<gen_event_filter> create_filter(
TEST(Ruleset, enable_disable_rules_using_names)
{
auto f = create_factory();
sinsp_filter_check_list filterlist;
auto f = create_factory(filterlist);
auto r = create_ruleset(f);
auto ast = create_ast(f);
auto filter = create_filter(f, ast);
@@ -119,7 +120,8 @@ TEST(Ruleset, enable_disable_rules_using_names)
TEST(Ruleset, enable_disable_rules_using_tags)
{
auto f = create_factory();
sinsp_filter_check_list filterlist;
auto f = create_factory(filterlist);
auto r = create_ruleset(f);
auto ast = create_ast(f);
auto filter = create_filter(f, ast);

View File

@@ -19,5 +19,5 @@ limitations under the License.
#include <falco/app/state.h>
#include <falco/app/actions/actions.h>
#define EXPECT_ACTION_OK(r) { EXPECT_TRUE(r.success); EXPECT_TRUE(r.proceed); EXPECT_EQ(r.errstr, ""); }
#define EXPECT_ACTION_FAIL(r) { EXPECT_FALSE(r.success); EXPECT_FALSE(r.proceed); EXPECT_NE(r.errstr, ""); }
#define EXPECT_ACTION_OK(r) { auto result = r; EXPECT_TRUE(result.success); EXPECT_TRUE(result.proceed); EXPECT_EQ(result.errstr, ""); }
#define EXPECT_ACTION_FAIL(r) { auto result = r; EXPECT_FALSE(result.success); EXPECT_FALSE(result.proceed); EXPECT_NE(result.errstr, ""); }

View File

@@ -77,11 +77,12 @@ static std::shared_ptr<falco_engine> mock_engine_from_filters(const strset_t& fi
}
// create a falco engine and load the ruleset
sinsp_filter_check_list filterlist;
std::shared_ptr<falco_engine> res(new falco_engine());
auto filter_factory = std::shared_ptr<gen_event_filter_factory>(
new sinsp_filter_factory(nullptr));
new sinsp_filter_factory(nullptr, filterlist));
auto formatter_factory = std::shared_ptr<gen_event_formatter_factory>(
new sinsp_evt_formatter_factory(nullptr));
new sinsp_evt_formatter_factory(nullptr, filterlist));
res->add_source(s_sample_source, filter_factory, formatter_factory);
res->load_rules(dummy_rules, "dummy_rules.yaml");
res->enable_rule("", true, s_sample_ruleset);

View File

@@ -27,30 +27,30 @@ TEST(ActionConfigureSyscallBufferNum, variable_number_of_CPUs)
FAIL() << "cannot get the number of online CPUs from the system\n";
}
// not modern bpf engine, we do nothing
// not modern ebpf engine, we do nothing
{
falco::app::state s;
s.options.modern_bpf = false;
s.config->m_engine_mode = engine_kind_t::MODERN_EBPF;
EXPECT_ACTION_OK(action(s));
}
// modern bpf engine, with an invalid number of CPUs
// modern ebpf engine, with an invalid number of CPUs
// default `m_cpus_for_each_syscall_buffer` to online CPU number
{
falco::app::state s;
s.options.modern_bpf = true;
s.config->m_cpus_for_each_syscall_buffer = online_cpus + 1;
s.config->m_engine_mode = engine_kind_t::MODERN_EBPF;
s.config->m_modern_ebpf.m_cpus_for_each_buffer = online_cpus + 1;
EXPECT_ACTION_OK(action(s));
EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, online_cpus);
EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_buffer, online_cpus);
}
// modern bpf engine, with an valid number of CPUs
// modern ebpf engine, with a valid number of CPUs
// we don't modify `m_cpus_for_each_syscall_buffer`
{
falco::app::state s;
s.options.modern_bpf = true;
s.config->m_cpus_for_each_syscall_buffer = online_cpus - 1;
s.config->m_engine_mode = engine_kind_t::MODERN_EBPF;
s.config->m_modern_ebpf.m_cpus_for_each_buffer = online_cpus - 1;
EXPECT_ACTION_OK(action(s));
EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, online_cpus - 1);
EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_buffer, online_cpus - 1);
}
}

View File

@@ -0,0 +1,196 @@
// SPDX-License-Identifier: Apache-2.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 ASSERTd 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 "app_action_helpers.h"
#include "falco_test_var.h"
#ifndef __EMSCRIPTEN__
TEST(ActionLoadConfig, check_engine_config_is_correctly_parsed)
{
falco::app::state s = {};
s.options.conf_filename = NEW_ENGINE_CONFIG_CHANGED;
EXPECT_ACTION_OK(falco::app::actions::load_config(s));
// Check that the engine is the kmod
EXPECT_TRUE(s.config->m_engine_mode == engine_kind_t::KMOD);
// Check that kmod params are the ones specified in the config
EXPECT_EQ(s.config->m_kmod.m_buf_size_preset, 2);
EXPECT_FALSE(s.config->m_kmod.m_drop_failed_exit);
// Check that all other engine params are empty
EXPECT_TRUE(s.config->m_ebpf.m_probe_path.empty());
EXPECT_EQ(s.config->m_ebpf.m_buf_size_preset, 0);
EXPECT_FALSE(s.config->m_ebpf.m_drop_failed_exit);
EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_buffer, 0);
EXPECT_EQ(s.config->m_modern_ebpf.m_buf_size_preset, 0);
EXPECT_FALSE(s.config->m_modern_ebpf.m_drop_failed_exit);
EXPECT_TRUE(s.config->m_replay.m_capture_file.empty());
EXPECT_TRUE(s.config->m_gvisor.m_config.empty());
EXPECT_TRUE(s.config->m_gvisor.m_root.empty());
// Check that deprecated configs are always set since
EXPECT_EQ(s.config->m_syscall_buf_size_preset, 6);
EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, 7);
EXPECT_TRUE(s.config->m_syscall_drop_failed_exit);
}
// Equal to the one above but checks that the command line options are not parsed
TEST(ActionLoadConfig, check_command_line_options_are_not_used)
{
falco::app::state s;
s.options.modern_bpf = true;
s.options.conf_filename = NEW_ENGINE_CONFIG_CHANGED;
EXPECT_ACTION_OK(falco::app::actions::load_config(s));
// Check that the engine is the kmod
EXPECT_TRUE(s.config->m_engine_mode == engine_kind_t::KMOD);
// Check that kmod params are the ones specified in the config
EXPECT_EQ(s.config->m_kmod.m_buf_size_preset, 2);
EXPECT_FALSE(s.config->m_kmod.m_drop_failed_exit);
// Check that all other engine params are empty
EXPECT_TRUE(s.config->m_ebpf.m_probe_path.empty());
EXPECT_EQ(s.config->m_ebpf.m_buf_size_preset, 0);
EXPECT_FALSE(s.config->m_ebpf.m_drop_failed_exit);
EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_buffer, 0);
EXPECT_EQ(s.config->m_modern_ebpf.m_buf_size_preset, 0);
EXPECT_FALSE(s.config->m_modern_ebpf.m_drop_failed_exit);
EXPECT_TRUE(s.config->m_replay.m_capture_file.empty());
EXPECT_TRUE(s.config->m_gvisor.m_config.empty());
EXPECT_TRUE(s.config->m_gvisor.m_root.empty());
// Check that deprecated configs are always set since
EXPECT_EQ(s.config->m_syscall_buf_size_preset, 6);
EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, 7);
EXPECT_TRUE(s.config->m_syscall_drop_failed_exit);
}
TEST(ActionLoadConfig, check_kmod_with_syscall_configs)
{
falco::app::state s;
s.options.conf_filename = NEW_ENGINE_CONFIG_UNCHANGED;
EXPECT_ACTION_OK(falco::app::actions::load_config(s));
// Check that the engine is the kmod
EXPECT_TRUE(s.config->m_engine_mode == engine_kind_t::KMOD);
// Kmod params should be populated with the syscall configs
// since the `engine` block is untouched.
EXPECT_EQ(s.config->m_kmod.m_buf_size_preset, 6);
EXPECT_TRUE(s.config->m_kmod.m_drop_failed_exit);
// Check that all other engine params are empty
EXPECT_TRUE(s.config->m_ebpf.m_probe_path.empty());
EXPECT_EQ(s.config->m_ebpf.m_buf_size_preset, 0);
EXPECT_FALSE(s.config->m_ebpf.m_drop_failed_exit);
EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_buffer, 0);
EXPECT_EQ(s.config->m_modern_ebpf.m_buf_size_preset, 0);
EXPECT_FALSE(s.config->m_modern_ebpf.m_drop_failed_exit);
EXPECT_TRUE(s.config->m_replay.m_capture_file.empty());
EXPECT_TRUE(s.config->m_gvisor.m_config.empty());
EXPECT_TRUE(s.config->m_gvisor.m_root.empty());
// Check that deprecated configs are populated
EXPECT_EQ(s.config->m_syscall_buf_size_preset, 6);
EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, 3);
EXPECT_TRUE(s.config->m_syscall_drop_failed_exit);
}
TEST(ActionLoadConfig, check_override_command_line_modern)
{
falco::app::state s;
// The command line options should be correctly applied since the
// config is unchanged
s.options.modern_bpf = true;
s.options.conf_filename = NEW_ENGINE_CONFIG_UNCHANGED;
EXPECT_ACTION_OK(falco::app::actions::load_config(s));
// Check that the engine is the kmod
EXPECT_TRUE(s.is_modern_ebpf());
// Check that the modern ebpf engine uses the default syscall configs
// and not the ones in the `engine` block
EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_buffer, 3);
EXPECT_EQ(s.config->m_modern_ebpf.m_buf_size_preset, 6);
EXPECT_TRUE(s.config->m_modern_ebpf.m_drop_failed_exit);
// Kmod params should be always populated since the kmod is the default
EXPECT_EQ(s.config->m_kmod.m_buf_size_preset, 6);
EXPECT_TRUE(s.config->m_kmod.m_drop_failed_exit);
// Check that all other engine params are empty
EXPECT_TRUE(s.config->m_ebpf.m_probe_path.empty());
EXPECT_EQ(s.config->m_ebpf.m_buf_size_preset, 0);
EXPECT_FALSE(s.config->m_ebpf.m_drop_failed_exit);
EXPECT_TRUE(s.config->m_replay.m_capture_file.empty());
EXPECT_TRUE(s.config->m_gvisor.m_config.empty());
EXPECT_TRUE(s.config->m_gvisor.m_root.empty());
// Check that deprecated configs are populated
EXPECT_EQ(s.config->m_syscall_buf_size_preset, 6);
EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, 3);
EXPECT_TRUE(s.config->m_syscall_drop_failed_exit);
}
TEST(ActionLoadConfig, check_override_command_line_gvisor)
{
falco::app::state s;
// The command line options should be correctly applied since the
// config is unchanged
s.options.gvisor_config = "config";
s.options.conf_filename = NEW_ENGINE_CONFIG_UNCHANGED;
EXPECT_ACTION_OK(falco::app::actions::load_config(s));
// Check that the engine is the kmod
EXPECT_TRUE(s.is_gvisor());
EXPECT_EQ(s.config->m_gvisor.m_config, "config");
EXPECT_TRUE(s.config->m_gvisor.m_root.empty());
// Kmod params should be always populated since the kmod is the default
EXPECT_EQ(s.config->m_kmod.m_buf_size_preset, 6);
EXPECT_TRUE(s.config->m_kmod.m_drop_failed_exit);
// Check that all other engine params are empty
EXPECT_TRUE(s.config->m_ebpf.m_probe_path.empty());
EXPECT_EQ(s.config->m_ebpf.m_buf_size_preset, 0);
EXPECT_FALSE(s.config->m_ebpf.m_drop_failed_exit);
EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_buffer, 0);
EXPECT_EQ(s.config->m_modern_ebpf.m_buf_size_preset, 0);
EXPECT_FALSE(s.config->m_modern_ebpf.m_drop_failed_exit);
EXPECT_TRUE(s.config->m_replay.m_capture_file.empty());
// Check that deprecated configs are populated
EXPECT_EQ(s.config->m_syscall_buf_size_preset, 6);
EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, 3);
EXPECT_TRUE(s.config->m_syscall_drop_failed_exit);
}
#endif

View File

@@ -30,7 +30,7 @@ TEST(ActionSelectEventSources, pre_post_conditions)
// ignore source selection in capture mode
{
falco::app::state s;
s.options.trace_filename = "some_capture_file.scap";
s.config->m_engine_mode = engine_kind_t::REPLAY;
EXPECT_TRUE(s.is_capture_mode());
EXPECT_ACTION_OK(action(s));
}

View File

@@ -0,0 +1,52 @@
# SPDX-License-Identifier: Apache-2.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.
#
################
# Falco engine #
################
engine:
kind: kmod
kmod:
buf_size_preset: 2 # changed default value
drop_failed_exit: false
ebpf:
probe: /path/to/probe.o
buf_size_preset: 4
drop_failed_exit: false
modern_ebpf:
cpus_for_each_buffer: 2
buf_size_preset: 4
drop_failed_exit: false
replay:
capture_file: /path/to/file.scap
gvisor:
config: /path/to/gvisor_config.yaml
root: ""
#######################################
# Falco performance tuning (advanced) #
#######################################
# These configs should be ignored since we have changed the `engine` config
syscall_buf_size_preset: 6
syscall_drop_failed_exit: true
modern_bpf:
cpus_for_each_syscall_buffer: 7

View File

@@ -0,0 +1,53 @@
# SPDX-License-Identifier: Apache-2.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.
#
################
# Falco engine #
################
# Unchanged
engine:
kind: kmod
kmod:
buf_size_preset: 4
drop_failed_exit: false
ebpf:
probe: /path/to/probe.o
buf_size_preset: 4
drop_failed_exit: false
modern_ebpf:
cpus_for_each_buffer: 2
buf_size_preset: 4
drop_failed_exit: false
replay:
capture_file: /path/to/file.scap
gvisor:
config: /path/to/gvisor_config.yaml
root: ""
#######################################
# Falco performance tuning (advanced) #
#######################################
# The `engine` config is unchanged so these configs are used
syscall_buf_size_preset: 6
syscall_drop_failed_exit: true
modern_bpf:
cpus_for_each_syscall_buffer: 3

View File

@@ -18,6 +18,12 @@ limitations under the License.
#include <gtest/gtest.h>
#include <falco/configuration.h>
#ifdef _WIN32
#define SET_ENV_VAR(env_var_name, env_var_value) _putenv_s(env_var_name, env_var_value)
#else
#define SET_ENV_VAR(env_var_name, env_var_value) setenv(env_var_name, env_var_value, 1)
#endif
static std::string sample_yaml =
"base_value:\n"
" id: 1\n"
@@ -108,17 +114,35 @@ 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;
SET_ENV_VAR(env_var_name.c_str(), env_var_value.c_str());
std::string sample_yaml =
std::string embedded_env_var_value = "${ENV_VAR}";
std::string embedded_env_var_name = "ENV_VAR_EMBEDDED";
SET_ENV_VAR(embedded_env_var_name.c_str(), embedded_env_var_value.c_str());
std::string bool_env_var_value = "true";
std::string bool_env_var_name = "ENV_VAR_BOOL";
SET_ENV_VAR(bool_env_var_name.c_str(), bool_env_var_value.c_str());
std::string int_env_var_value = "12";
std::string int_env_var_name = "ENV_VAR_INT";
SET_ENV_VAR(int_env_var_name.c_str(), int_env_var_value.c_str());
std::string empty_env_var_value = "";
std::string empty_env_var_name = "ENV_VAR_EMPTY";
SET_ENV_VAR(empty_env_var_name.c_str(), empty_env_var_value.c_str());
std::string default_value = "default";
std::string env_var_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"
" invalid_env: $$ENV_VAR\n"
" invalid_double_env: $${ENV_VAR}$${ENV_VAR}\n"
" invalid_embedded_env: $${${ENV_VAR}}\n"
" invalid_valid_env: $${ENV_VAR}${ENV_VAR}\n"
" escaped: \"${ENV_VAR}\"\n"
" subvalue:\n"
" subvalue2:\n"
@@ -127,50 +151,213 @@ TEST(Configuration, configuration_environment_variables)
" sample_list:\n"
" - ${ENV_VAR}\n"
" - ' ${ENV_VAR}'\n"
" - $UNSED_XX_X_X_VAR\n";
conf.load_from_string(sample_yaml);
" - '${ENV_VAR} '\n"
" - $UNSED_XX_X_X_VAR\n"
"paths:\n"
" - ${ENV_VAR}/foo\n"
" - $ENV_VAR/foo\n"
" - /foo/${ENV_VAR}/\n"
" - /${ENV_VAR}/${ENV_VAR}${ENV_VAR}/foo\n"
" - ${ENV_VAR_EMBEDDED}/foo\n"
"is_test: ${ENV_VAR_BOOL}\n"
"num_test: ${ENV_VAR_INT}\n"
"empty_test: ${ENV_VAR_EMPTY}\n"
"plugins:\n"
" - name: k8saudit\n"
" library_path: /foo/${ENV_VAR}/libk8saudit.so\n"
" open_params: ${ENV_VAR_INT}\n";
yaml_helper conf;
conf.load_from_string(env_var_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_TRUE(conf.is_defined("paths"));
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);
auto 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);
auto 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);
/* Test fetching of invalid escaped environment variable format. Should return the string as-is */
auto 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 2 escaped environment variables side by side. Should return the string as-is after stripping the leading `$` */
auto base_value_double_invalid = conf.get_scalar<std::string>("base_value.invalid_double_env", default_value);
ASSERT_EQ(base_value_double_invalid, "${ENV_VAR}${ENV_VAR}");
/*
* Test fetching of escaped environment variable format with inside an env variable.
* Should return the string as-is after stripping the leading `$` with the resolved env variable within
*/
auto base_value_embedded_invalid = conf.get_scalar<std::string>("base_value.invalid_embedded_env", default_value);
ASSERT_EQ(base_value_embedded_invalid, "${" + env_var_value + "}");
/*
* Test fetching of an escaped env variable plus an env variable side by side.
* Should return the escaped one trimming the leading `$` plus the second one resolved.
*/
auto base_value_valid_invalid = conf.get_scalar<std::string>("base_value.invalid_valid_env", default_value);
ASSERT_EQ(base_value_valid_invalid, "${ENV_VAR}" + env_var_value);
/* Test fetching of strings that contain environment variables */
std::string base_value_id = conf.get_scalar<std::string>("base_value.id", default_value);
auto 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);
auto 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);
auto 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 an undefined environment variable. Resolves to empty string. */
auto unknown_boolean = conf.get_scalar<std::string>("base_value.subvalue.subvalue2.boolean", default_value);
ASSERT_EQ(unknown_boolean, "");
/* 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);
auto 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
auto 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_value); // Environment variable preceded by a space, still extracted env var with leading space
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
auto 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, env_var_value + " "); // Environment variable followed by a space, still extracted env var with trailing space
/* Clear the set environment variable after testing */
unsetenv(env_var_name.c_str());
auto base_value_2_list_3 = conf.get_scalar<std::string>("base_value_2.sample_list[3]", default_value);
ASSERT_EQ(base_value_2_list_3, "$UNSED_XX_X_X_VAR"); // Does not follow the `${VAR}` format, so should be treated as a regular string
/* Test expansion of environment variables within strings */
auto path_list_0 = conf.get_scalar<std::string>("paths[0]", default_value);
ASSERT_EQ(path_list_0, env_var_value + "/foo"); // Even if env var is part of bigger string, it gets expanded
auto path_list_1 = conf.get_scalar<std::string>("paths[1]", default_value);
ASSERT_EQ(path_list_1, "$ENV_VAR/foo"); // Does not follow the `${VAR}` format, so should be treated as a regular string
auto path_list_2 = conf.get_scalar<std::string>("paths[2]", default_value);
ASSERT_EQ(path_list_2, "/foo/" + env_var_value + "/"); // Even when env var is in the middle of a string. it gets expanded
auto path_list_3 = conf.get_scalar<std::string>("paths[3]", default_value);
ASSERT_EQ(path_list_3, "/" + env_var_value + "/" + env_var_value + env_var_value + "/foo"); // Even when the string contains multiple env vars they are correctly expanded
auto path_list_4 = conf.get_scalar<std::string>("paths[4]", default_value);
ASSERT_EQ(path_list_4, env_var_value + "/foo"); // Even when the env var contains another env var, it gets correctly double-expanded
/* Check that variable expansion is type-aware */
auto boolean = conf.get_scalar<bool>("is_test", false);
ASSERT_EQ(boolean, true); // `true` can be parsed to bool.
auto boolean_as_str = conf.get_scalar<std::string>("is_test", "false");
ASSERT_EQ(boolean_as_str, "true"); // `true` can be parsed to string.
auto boolean_as_int = conf.get_scalar<int32_t>("is_test", 0);
ASSERT_EQ(boolean_as_int, 0); // `true` cannot be parsed to integer.
auto integer = conf.get_scalar<int32_t>("num_test", -1);
ASSERT_EQ(integer, 12);
// An env var that resolves to an empty string returns ""
auto empty_default_str = conf.get_scalar<std::string>("empty_test", default_value);
ASSERT_EQ(empty_default_str, "");
std::list<falco_configuration::plugin_config> plugins;
conf.get_sequence<std::list<falco_configuration::plugin_config>>(plugins, std::string("plugins"));
std::vector<falco_configuration::plugin_config> m_plugins{ std::make_move_iterator(std::begin(plugins)),
std::make_move_iterator(std::end(plugins)) };
ASSERT_EQ(m_plugins[0].m_name, "k8saudit");
ASSERT_EQ(m_plugins[0].m_library_path, "/foo/" + env_var_value + "/libk8saudit.so");
ASSERT_EQ(m_plugins[0].m_open_params, "12");
/* Clear the set environment variables after testing */
SET_ENV_VAR(env_var_name.c_str(), "");
SET_ENV_VAR(embedded_env_var_name.c_str(), "");
SET_ENV_VAR(bool_env_var_name.c_str(), "");
SET_ENV_VAR(int_env_var_name.c_str(), "");
SET_ENV_VAR(empty_env_var_name.c_str(), "");
}
TEST(Configuration, configuration_webserver_ip)
{
falco_configuration falco_config;
std::vector<std::string> valid_addresses = {"127.0.0.1",
"1.127.0.1",
"1.1.127.1",
"1.1.1.127",
"::",
"::1",
"1200:0000:AB00:1234:0000:2552:7777:1313",
"1200::AB00:1234:0000:2552:7777:1313",
"1200:0000:AB00:1234::2552:7777:1313",
"21DA:D3:0:2F3B:2AA:FF:FE28:9C5A",
"FE80:0000:0000:0000:0202:B3FF:FE1E:8329",
"0.0.0.0",
"9.255.255.255",
"11.0.0.0",
"126.255.255.255",
"129.0.0.0",
"169.253.255.255",
"169.255.0.0",
"172.15.255.255",
"172.32.0.0",
"191.0.1.255",
"192.88.98.255",
"192.88.100.0",
"192.167.255.255",
"192.169.0.0",
"198.17.255.255",
"223.255.255.255"};
for (const std::string &address: valid_addresses) {
std::string option = "webserver.listen_address=";
option.append(address);
std::vector<std::string> cmdline_config_options;
cmdline_config_options.push_back(option);
EXPECT_NO_THROW(falco_config.init(cmdline_config_options));
ASSERT_EQ(falco_config.m_webserver_listen_address, address);
}
std::vector<std::string> invalid_addresses = {"327.0.0.1",
"1.327.0.1",
"1.1.327.1",
"1.1.1.327",
"12 7.0.0.1",
"127. 0.0.1",
"127.0. 0.1",
"127.0.0. 1",
"!27.0.0.1",
"1200: 0000:AB00:1234:0000:2552:7777:1313",
"1200:0000: AB00:1234:0000:2552:7777:1313",
"1200:0000:AB00: 1234:0000:2552:7777:1313",
"1200:0000:AB00:1234: 0000:2552:7777:1313",
"1200:0000:AB00:1234:0000: 2552:7777:1313",
"1200:0000:AB00:1234:0000:2552: 7777:1313",
"1200:0000:AB00:1234:0000:2552:7777: 1313",
"1200:0000:AB00:1234:0000:2552:7777:131G",
"1200:0000:AB00:1234:0000:2552:77Z7:1313",
"1200:0000:AB00:1234:0000:2G52:7777:1313",
"1200:0000:AB00:1234:0O00:2552:7777:1313",
"1200:0000:AB00:H234:0000:2552:7777:1313",
"1200:0000:IB00:1234:0000:2552:7777:1313",
"1200:0O00:AB00:1234:0000:2552:7777:1313",
"12O0:0000:AB00:1234:0000:2552:7777:1313",};
for (const std::string &address: invalid_addresses) {
std::string option = "webserver.listen_address=";
option.append(address);
std::vector<std::string> cmdline_config_options;
cmdline_config_options.push_back(option);
EXPECT_ANY_THROW(falco_config.init(cmdline_config_options));
}
}

View File

@@ -0,0 +1,4 @@
#pragma once
#define NEW_ENGINE_CONFIG_CHANGED "${CMAKE_SOURCE_DIR}/unit_tests/falco/test_configs/new_engine_config_changed.yaml"
#define NEW_ENGINE_CONFIG_UNCHANGED "${CMAKE_SOURCE_DIR}/unit_tests/falco/test_configs/new_engine_config_unchanged.yaml"

View File

@@ -11,12 +11,11 @@
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
set(FALCO_ENGINE_SOURCE_FILES
add_library(falco_engine STATIC
falco_common.cpp
falco_engine.cpp
falco_load_result.cpp
falco_utils.cpp
json_evt.cpp
evttype_index_ruleset.cpp
formats.cpp
filter_details_resolver.cpp
@@ -26,9 +25,8 @@ set(FALCO_ENGINE_SOURCE_FILES
rule_loader.cpp
rule_loader_reader.cpp
rule_loader_collector.cpp
rule_loader_compiler.cpp)
add_library(falco_engine STATIC ${FALCO_ENGINE_SOURCE_FILES})
rule_loader_compiler.cpp
)
if (EMSCRIPTEN)
target_compile_options(falco_engine PRIVATE "-sDISABLE_EXCEPTION_CATCHING=0")
@@ -36,26 +34,17 @@ endif()
add_dependencies(falco_engine yamlcpp njson)
if(MINIMAL_BUILD)
target_include_directories(
falco_engine
PUBLIC
"${NJSON_INCLUDE}"
"${TBB_INCLUDE_DIR}"
"${LIBSCAP_INCLUDE_DIRS}"
"${LIBSINSP_INCLUDE_DIRS}"
"${YAMLCPP_INCLUDE_DIR}"
"${PROJECT_BINARY_DIR}/userspace/engine")
else()
target_include_directories(
falco_engine
PUBLIC
"${NJSON_INCLUDE}"
"${TBB_INCLUDE_DIR}"
"${LIBSCAP_INCLUDE_DIRS}"
"${LIBSINSP_INCLUDE_DIRS}"
"${YAMLCPP_INCLUDE_DIR}"
"${PROJECT_BINARY_DIR}/userspace/engine")
endif()
target_include_directories(falco_engine
PUBLIC
${LIBSCAP_INCLUDE_DIRS}
${LIBSINSP_INCLUDE_DIRS}
${PROJECT_BINARY_DIR}/userspace/engine
${nlohmann_json_INCLUDE_DIRS}
${TBB_INCLUDE_DIR}
${YAMLCPP_INCLUDE_DIR}
)
target_link_libraries(falco_engine "${FALCO_SINSP_LIBRARY}" "${YAMLCPP_LIB}")
target_link_libraries(falco_engine
${FALCO_SINSP_LIBRARY}
${YAMLCPP_LIB}
)

View File

@@ -1,48 +0,0 @@
// SPDX-License-Identifier: Apache-2.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.
*/
#pragma once
// BAN macro defines `function` as an invalid token that says using
// the function is banned. This throws a compile time error when the
// function is used.
#define BAN(function) using_##function##_is_banned
// BAN_ALTERNATIVE is same as BAN but the message also provides an alternative
// function that the user could use instead of the banned function.
#define BAN_ALTERNATIVE(function, alternative) using_##function##_is_banned__use_##alternative##_instead
#undef strcpy
#define strcpy(a, b) BAN(strcpy)
#undef vsprintf
#define vsprintf(a, b, c) BAN_ALTERNATIVE(vsprintf, vsnprintf)
#undef sprintf
#define sprintf(a, b, ...) BAN_ALTERNATIVE(sprintf, snprintf)
#undef strcat
#define strcat(a, b) BAN(strcat)
#undef strncpy
#define strncpy(a, b, c) BAN(strncpy)
#undef swprintf
#define swprintf(a, b, c, ...) BAN_ALTERNATIVE(swprintf, snprintf)
#undef vswprintf
#define vswprintf(a, b, c, d) BAN_ALTERNATIVE(vswprintf, vsnprintf)

View File

@@ -16,7 +16,6 @@ limitations under the License.
*/
#include "evttype_index_ruleset.h"
#include "banned.h" // This raises a compilation error when certain functions are used
#include <algorithm>

View File

@@ -44,9 +44,7 @@ limitations under the License.
#include "formats.h"
#include "utils.h"
#include "banned.h" // This raises a compilation error when certain functions are used
#include "evttype_index_ruleset.h"
#include "filter_details_resolver.h"
const std::string falco_engine::s_default_ruleset = "falco-default-ruleset";
@@ -76,29 +74,9 @@ falco_engine::~falco_engine()
m_sources.clear();
}
uint32_t falco_engine::engine_version()
sinsp_version falco_engine::engine_version()
{
return (uint32_t) FALCO_ENGINE_VERSION;
}
const falco_source* falco_engine::find_source(const std::string& name) const
{
auto ret = m_sources.at(name);
if(!ret)
{
throw falco_exception("Unknown event source " + name);
}
return ret;
}
const falco_source* falco_engine::find_source(std::size_t index) const
{
auto ret = m_sources.at(index);
if(!ret)
{
throw falco_exception("Unknown event source index " + std::to_string(index));
}
return ret;
return sinsp_version(FALCO_ENGINE_VERSION);
}
// Return a key that uniquely represents a field class.
@@ -179,34 +157,63 @@ void falco_engine::list_fields(std::string &source, bool verbose, bool names_onl
}
}
void falco_engine::load_rules(const std::string &rules_content, bool verbose, bool all_events)
{
static const std::string no_name = "N/A";
std::unique_ptr<load_result> res = load_rules(rules_content, no_name);
interpret_load_result(res, no_name, rules_content, verbose);
}
std::unique_ptr<load_result> falco_engine::load_rules(const std::string &rules_content, const std::string &name)
{
rule_loader::configuration cfg(rules_content, m_sources, name);
cfg.min_priority = m_min_priority;
cfg.output_extra = m_extra;
cfg.replace_output_container_info = m_replace_container_info;
cfg.default_ruleset_id = m_default_ruleset_id;
// read rules YAML file and collect its definitions
rule_loader::reader reader;
if (reader.read(cfg, m_rule_collector))
{
// compile the definitions (resolve macro/list refs, exceptions, ...)
m_last_compile_output = std::make_unique<rule_loader::compiler::compile_output>();
rule_loader::compiler().compile(cfg, m_rule_collector, *m_last_compile_output.get());
// clear the rules known by the engine and each ruleset
m_rules.clear();
for (auto &src : m_sources)
{
src.ruleset = src.ruleset_factory->new_ruleset();
}
rule_loader::compiler compiler;
m_rules.clear();
compiler.compile(cfg, m_rule_collector, m_rules);
// add rules to the engine and the rulesets
for (const auto& rule : m_last_compile_output->rules)
{
// skip the rule if below the minimum priority
if (rule.priority > m_min_priority)
{
continue;
}
auto info = m_rule_collector.rules().at(rule.name);
if (!info)
{
// this is just defensive, it should never happen
throw falco_exception("can't find internal rule info at name: " + name);
}
// the rule is ok, we can add it to the engine and the rulesets
// note: the compiler should guarantee that the rule's condition
// is a valid sinsp filter
auto source = find_source(rule.source);
std::shared_ptr<gen_event_filter> filter(
sinsp_filter_compiler(source->filter_factory, rule.condition.get()).compile());
auto rule_id = m_rules.insert(rule, rule.name);
m_rules.at(rule_id)->id = rule_id;
source->ruleset->add(rule, filter, rule.condition);
// By default rules are enabled/disabled for the default ruleset
if(info->enabled)
{
source->ruleset->enable(rule.name, true, m_default_ruleset_id);
}
else
{
source->ruleset->disable(rule.name, true, m_default_ruleset_id);
}
}
}
if (cfg.res->successful())
@@ -221,47 +228,15 @@ std::unique_ptr<load_result> falco_engine::load_rules(const std::string &rules_c
return std::move(cfg.res);
}
void falco_engine::load_rules_file(const std::string &rules_filename, bool verbose, bool all_events)
{
std::string rules_content;
read_file(rules_filename, rules_content);
std::unique_ptr<load_result> res = load_rules(rules_content, rules_filename);
interpret_load_result(res, rules_filename, rules_content, verbose);
}
std::unique_ptr<load_result> falco_engine::load_rules_file(const std::string &rules_filename)
{
std::string rules_content;
try {
read_file(rules_filename, rules_content);
}
catch (falco_exception &e)
{
rule_loader::context ctx(rules_filename);
std::unique_ptr<rule_loader::result> res(new rule_loader::result(rules_filename));
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);
}
void falco_engine::enable_rule(const std::string &substring, bool enabled, const std::string &ruleset)
{
uint16_t ruleset_id = find_ruleset_id(ruleset);
enable_rule(substring, enabled, ruleset_id);
}
void falco_engine::enable_rule(const std::string &substring, bool enabled, const uint16_t ruleset_id)
{
bool match_exact = false;
for(const auto &it : m_sources)
@@ -280,6 +255,12 @@ void falco_engine::enable_rule(const std::string &substring, bool enabled, const
void falco_engine::enable_rule_exact(const std::string &rule_name, bool enabled, const std::string &ruleset)
{
uint16_t ruleset_id = find_ruleset_id(ruleset);
enable_rule_exact(rule_name, enabled, ruleset_id);
}
void falco_engine::enable_rule_exact(const std::string &rule_name, bool enabled, const uint16_t ruleset_id)
{
bool match_exact = true;
for(const auto &it : m_sources)
@@ -299,6 +280,11 @@ void falco_engine::enable_rule_by_tag(const std::set<std::string> &tags, bool en
{
uint16_t ruleset_id = find_ruleset_id(ruleset);
enable_rule_by_tag(tags, enabled, ruleset_id);
}
void falco_engine::enable_rule_by_tag(const std::set<std::string> &tags, bool enabled, const uint16_t ruleset_id)
{
for(const auto &it : m_sources)
{
if(enabled)
@@ -348,7 +334,7 @@ libsinsp::events::set<ppm_sc_code> falco_engine::sc_codes_for_ruleset(const std:
{
return find_source(source)->ruleset->enabled_sc_codes(find_ruleset_id(ruleset));
}
libsinsp::events::set<ppm_event_code> falco_engine::event_codes_for_ruleset(const std::string &source, const std::string &ruleset)
{
return find_source(source)->ruleset->enabled_event_codes(find_ruleset_id(ruleset));
@@ -369,21 +355,7 @@ std::unique_ptr<std::vector<falco_engine::rule_result>> falco_engine::process_ev
// source_idx, which means that at any time each filter_ruleset will only
// be accessed by a single thread.
const falco_source *source;
if(source_idx == m_syscall_source_idx)
{
if(m_syscall_source == NULL)
{
m_syscall_source = find_source(m_syscall_source_idx);
}
source = m_syscall_source;
}
else
{
source = find_source(source_idx);
}
const falco_source *source = find_source(source_idx);
if(should_drop_evt() || !source)
{
@@ -469,106 +441,88 @@ std::size_t falco_engine::add_source(const std::string &source,
return m_sources.insert(src, source);
}
void falco_engine::describe_rule(std::string *rule, bool json) const
template <typename T> inline nlohmann::json sequence_to_json_array(const T& seq)
{
if(!json)
nlohmann::json ret = nlohmann::json::array();
for (const auto& v : seq)
{
static const char *rule_fmt = "%-50s %s\n";
fprintf(stdout, rule_fmt, "Rule", "Description");
fprintf(stdout, rule_fmt, "----", "-----------");
if(!rule)
{
for(auto &r : m_rules)
{
auto str = falco::utils::wrap_text(r.description, 51, 110) + "\n";
fprintf(stdout, rule_fmt, r.name.c_str(), str.c_str());
}
}
else
{
auto r = m_rules.at(*rule);
if(r == nullptr)
{
return;
}
auto str = falco::utils::wrap_text(r->description, 51, 110) + "\n";
fprintf(stdout, rule_fmt, r->name.c_str(), str.c_str());
}
ret.push_back(v);
}
return ret;
}
return;
nlohmann::json falco_engine::describe_rule(std::string *rule, const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const
{
// use previously-loaded collector definitions and the compiled
// output of rules, macros, and lists.
if (m_last_compile_output == nullptr)
{
throw falco_exception("rules must be loaded before describing them");
}
std::unique_ptr<sinsp> insp(new sinsp());
Json::FastWriter writer;
std::string json_str;
// use collected and compiled info to print a json output
nlohmann::json output;
if(!rule)
{
// In this case we build json information about
// all rules, macros and lists
Json::Value output;
// Store required engine version
auto required_engine_version = m_rule_collector.required_engine_version();
output["required_engine_version"] = std::to_string(required_engine_version.version);
output["required_engine_version"] = required_engine_version.version.as_string();
// Store required plugin versions
Json::Value plugin_versions = Json::arrayValue;
nlohmann::json plugin_versions = nlohmann::json::array();
auto required_plugin_versions = m_rule_collector.required_plugin_versions();
for(const auto& req : required_plugin_versions)
{
Json::Value r;
nlohmann::json r;
r["name"] = req.at(0).name;
r["version"] = req.at(0).version;
Json::Value alternatives = Json::arrayValue;
nlohmann::json alternatives = nlohmann::json::array();
for(size_t i = 1; i < req.size(); i++)
{
Json::Value alternative;
nlohmann::json alternative;
alternative["name"] = req[i].name;
alternative["version"] = req[i].version;
alternatives.append(alternative);
alternatives.push_back(std::move(alternative));
}
r["alternatives"] = alternatives;
plugin_versions.append(r);
r["alternatives"] = std::move(alternatives);
plugin_versions.push_back(std::move(r));
}
output["required_plugin_versions"] = plugin_versions;
output["required_plugin_versions"] = std::move(plugin_versions);
// Store information about rules
Json::Value rules_array = Json::arrayValue;
for(const auto& r : m_rules)
nlohmann::json rules_array = nlohmann::json::array();
for(const auto& r : m_last_compile_output->rules)
{
auto ri = m_rule_collector.rules().at(r.name);
Json::Value rule;
get_json_details(r, *ri, insp.get(), rule);
// Append to rule array
rules_array.append(rule);
auto info = m_rule_collector.rules().at(r.name);
nlohmann::json rule;
get_json_details(rule, r, *info, plugins);
rules_array.push_back(std::move(rule));
}
output["rules"] = rules_array;
output["rules"] = std::move(rules_array);
// Store information about macros
Json::Value macros_array;
for(const auto &m : m_rule_collector.macros())
nlohmann::json macros_array = nlohmann::json::array();
for(const auto &m : m_last_compile_output->macros)
{
Json::Value macro;
get_json_details(m, macro);
macros_array.append(macro);
auto info = m_rule_collector.macros().at(m.name);
nlohmann::json macro;
get_json_details(macro, m, *info, plugins);
macros_array.push_back(std::move(macro));
}
output["macros"] = macros_array;
output["macros"] = std::move(macros_array);
// Store information about lists
Json::Value lists_array = Json::arrayValue;
for(const auto &l : m_rule_collector.lists())
// Store information about lists
nlohmann::json lists_array = nlohmann::json::array();
for(const auto &l : m_last_compile_output->lists)
{
Json::Value list;
get_json_details(l, list);
lists_array.append(list);
auto info = m_rule_collector.lists().at(l.name);
nlohmann::json list;
get_json_details(list, l, *info, plugins);
lists_array.push_back(std::move(list));
}
output["lists"] = lists_array;
json_str = writer.write(output);
output["lists"] = std::move(lists_array);
}
else
{
@@ -579,69 +533,77 @@ void falco_engine::describe_rule(std::string *rule, bool json) const
throw falco_exception("Rule \"" + *rule + "\" is not loaded");
}
auto r = m_rules.at(ri->name);
Json::Value rule;
get_json_details(*r, *ri, insp.get(), rule);
json_str = writer.write(rule);
nlohmann::json rule;
get_json_details(rule, *r, *ri, plugins);
nlohmann::json rules_array = nlohmann::json::array();
rules_array.push_back(std::move(rule));
output["rules"] = std::move(rules_array);
}
fprintf(stdout, "%s", json_str.c_str());
return output;
}
void falco_engine::get_json_details(const falco_rule &r,
const rule_loader::rule_info &ri,
sinsp *insp,
Json::Value &rule) const
void falco_engine::get_json_details(
nlohmann::json &out,
const falco_rule &r,
const rule_loader::rule_info &info,
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const
{
Json::Value rule_info;
nlohmann::json rule_info;
// Fill general rule information
rule_info["name"] = r.name;
rule_info["condition"] = ri.cond;
rule_info["condition"] = info.cond;
rule_info["priority"] = format_priority(r.priority, false);
rule_info["output"] = r.output;
rule_info["output"] = info.output;
rule_info["description"] = r.description;
rule_info["enabled"] = ri.enabled;
rule_info["enabled"] = info.enabled;
rule_info["source"] = r.source;
Json::Value tags = Json::arrayValue;
for(const auto &t : ri.tags)
{
tags.append(t);
}
rule_info["tags"] = tags;
rule["info"] = rule_info;
rule_info["tags"] = sequence_to_json_array(info.tags);
out["info"] = std::move(rule_info);
// Parse rule condition and build the AST
// Assumption: no exception because rules have already been loaded.
auto ast = libsinsp::filter::parser(ri.cond).parse();
Json::Value json_details;
get_json_details(ast.get(), json_details);
rule["details"] = json_details;
// Parse rule condition and build the non-compiled AST
// Assumption: no error because rules have already been loaded.
auto ast = libsinsp::filter::parser(info.cond).parse();
// get details related to the condition's filter
filter_details details;
filter_details compiled_details;
nlohmann::json json_details;
for(const auto &m : m_rule_collector.macros())
{
details.known_macros.insert(m.name);
compiled_details.known_macros.insert(m.name);
}
for(const auto &l : m_rule_collector.lists())
{
details.known_lists.insert(l.name);
compiled_details.known_lists.insert(l.name);
}
filter_details_resolver().run(ast.get(), details);
filter_details_resolver().run(r.condition.get(), compiled_details);
out["details"]["macros"] = sequence_to_json_array(details.macros);
out["details"]["lists"] = sequence_to_json_array(details.lists);
out["details"]["condition_operators"] = sequence_to_json_array(compiled_details.operators);
out["details"]["condition_fields"] = sequence_to_json_array(compiled_details.fields);
// Get fields from output string
auto fmt = create_formatter(r.source, r.output);
std::vector<std::string> out_fields;
fmt->get_field_names(out_fields);
Json::Value outputFields = Json::arrayValue;
for(const auto &of : out_fields)
{
outputFields.append(of);
}
rule["details"]["output_fields"] = outputFields;
out["details"]["output_fields"] = sequence_to_json_array(out_fields);
// Get fields from exceptions
Json::Value exception_fields = Json::arrayValue;
for(const auto &f : r.exception_fields)
{
exception_fields.append(f);
}
rule["details"]["exception_fields"] = exception_fields;
out["details"]["exception_fields"] = sequence_to_json_array(r.exception_fields);
// Get names and operators from exceptions
Json::Value exception_names = Json::arrayValue;
Json::Value exception_operators = Json::arrayValue;
for(const auto &e : ri.exceptions)
std::unordered_set<std::string> exception_names;
std::unordered_set<std::string> exception_operators;
for(const auto &e : info.exceptions)
{
exception_names.append(e.name);
exception_names.insert(e.name);
if(e.comps.is_list)
{
for(const auto& c : e.comps.items)
@@ -651,140 +613,239 @@ void falco_engine::get_json_details(const falco_rule &r,
// considering max two levels of lists
for(const auto& i : c.items)
{
exception_operators.append(i.item);
exception_operators.insert(i.item);
}
}
else
{
exception_operators.append(c.item);
exception_operators.insert(c.item);
}
}
}
else
{
exception_operators.append(e.comps.item);
}
exception_operators.insert(e.comps.item);
}
}
rule["details"]["exceptions"] = exception_names;
rule["details"]["exception_operators"] = exception_operators;
if(ri.source == falco_common::syscall_source)
{
// Store event types
Json::Value events;
get_json_evt_types(ast.get(), events);
rule["details"]["events"] = events;
}
}
void falco_engine::get_json_details(const rule_loader::macro_info& m,
Json::Value& macro) const
{
Json::Value macro_info;
macro_info["name"] = m.name;
macro_info["condition"] = m.cond;
macro["info"] = macro_info;
// Assumption: no exception because rules have already been loaded.
auto ast = libsinsp::filter::parser(m.cond).parse();
Json::Value json_details;
get_json_details(ast.get(), json_details);
macro["details"] = json_details;
out["details"]["exception_names"] = sequence_to_json_array(exception_names);
out["details"]["exception_operators"] = sequence_to_json_array(exception_operators);
// Store event types
Json::Value events;
get_json_evt_types(ast.get(), events);
macro["details"]["events"] = events;
nlohmann::json events;
get_json_evt_types(events, info.source, r.condition.get());
out["details"]["events"] = std::move(events);
// Store compiled condition and output
out["details"]["condition_compiled"] = libsinsp::filter::ast::as_string(r.condition.get());
out["details"]["output_compiled"] = r.output;
// Compute the plugins that are actually used by this rule. This is involves:
// - The rule's event source, that can be implemented by a plugin
// - The fields used in the rule's condition, output, and exceptions
// - The evt types used in the rule's condition checks, that can potentially
// match plugin-provided async events
nlohmann::json used_plugins;
// note: making a union of conditions's and output's fields
// note: the condition's AST accounts for all the resolved refs and exceptions
compiled_details.fields.insert(out_fields.begin(), out_fields.end());
get_json_used_plugins(used_plugins, info.source, compiled_details.evtnames, compiled_details.fields, plugins);
out["details"]["plugins"] = std::move(used_plugins);
}
void falco_engine::get_json_details(const rule_loader::list_info& l,
Json::Value& list) const
void falco_engine::get_json_details(
nlohmann::json& out,
const falco_macro& m,
const rule_loader::macro_info& info,
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const
{
Json::Value list_info;
list_info["name"] = l.name;
nlohmann::json macro_info;
Json::Value items = Json::arrayValue;
Json::Value lists = Json::arrayValue;
for(const auto &i : l.items)
{
if(m_rule_collector.lists().at(i) != nullptr)
{
lists.append(i);
continue;
}
items.append(i);
}
macro_info["name"] = m.name;
macro_info["condition"] = info.cond;
out["info"] = std::move(macro_info);
list_info["items"] = items;
list["info"] = list_info;
list["details"]["lists"] = lists;
}
// Parse the macro condition and build the non-compiled AST
// Assumption: no exception because rules have already been loaded.
auto ast = libsinsp::filter::parser(info.cond).parse();
void falco_engine::get_json_details(libsinsp::filter::ast::expr* ast,
Json::Value& output) const
{
// get details related to the condition's filter
filter_details details;
filter_details compiled_details;
nlohmann::json json_details;
for(const auto &m : m_rule_collector.macros())
{
details.known_macros.insert(m.name);
compiled_details.known_macros.insert(m.name);
}
for(const auto &l : m_rule_collector.lists())
{
details.known_lists.insert(l.name);
compiled_details.known_lists.insert(l.name);
}
filter_details_resolver().run(ast.get(), details);
filter_details_resolver().run(m.condition.get(), compiled_details);
// Resolve the AST details
filter_details_resolver resolver;
resolver.run(ast, details);
out["details"]["used"] = m.used;
out["details"]["macros"] = sequence_to_json_array(details.macros);
out["details"]["lists"] = sequence_to_json_array(details.lists);
out["details"]["condition_operators"] = sequence_to_json_array(compiled_details.operators);
out["details"]["condition_fields"] = sequence_to_json_array(compiled_details.fields);
Json::Value macros = Json::arrayValue;
for(const auto &m : details.macros)
{
macros.append(m);
}
output["macros"] = macros;
// Store event types
nlohmann::json events;
get_json_evt_types(events, "", m.condition.get());
out["details"]["events"] = std::move(events);
Json::Value operators = Json::arrayValue;
for(const auto &o : details.operators)
{
operators.append(o);
}
output["operators"] = operators;
// Store compiled condition
out["details"]["condition_compiled"] = libsinsp::filter::ast::as_string(m.condition.get());
Json::Value condition_fields = Json::arrayValue;
for(const auto &f : details.fields)
{
condition_fields.append(f);
}
output["condition_fields"] = condition_fields;
Json::Value lists = Json::arrayValue;
for(const auto &l : details.lists)
{
lists.append(l);
}
output["lists"] = lists;
details.reset();
// Compute the plugins that are actually used by this macro.
// Note: macros have no specific source, we need to set an empty list of used
// plugins because we can't be certain about their actual usage. For example,
// if a macro uses a plugin's field, we can't be sure which plugin actually
// is used until we resolve the macro ref in a rule providing a source for
// disambiguation.
out["details"]["plugins"] = nlohmann::json::array();
}
void falco_engine::get_json_evt_types(libsinsp::filter::ast::expr* ast,
Json::Value& output) const
void falco_engine::get_json_details(
nlohmann::json& out,
const falco_list& l,
const rule_loader::list_info& info,
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const
{
output = Json::arrayValue;
auto evtcodes = libsinsp::filter::ast::ppm_event_codes(ast);
auto syscodes = libsinsp::filter::ast::ppm_sc_codes(ast);
auto syscodes_to_evt_names = libsinsp::events::sc_set_to_event_names(syscodes);
auto evtcodes_to_evt_names = libsinsp::events::event_set_to_names(evtcodes, false);
for (const auto& n : unordered_set_union(syscodes_to_evt_names, evtcodes_to_evt_names))
nlohmann::json list_info;
list_info["name"] = l.name;
// note: the syntactic definitions still has the list refs unresolved
nlohmann::json items = nlohmann::json::array();
std::unordered_set<std::string> lists;
for(const auto &i : info.items)
{
output.append(n);
// if an item is present in the syntactic def of a list, but not
// on the compiled_items of the same list, then we can assume it
// being a resolved list ref
if(std::find(l.items.begin(), l.items.end(), i) == l.items.end())
{
lists.insert(i);
continue;
}
items.push_back(std::move(i));
}
list_info["items"] = std::move(items);
out["info"] = std::move(list_info);
out["details"]["used"] = l.used;
out["details"]["lists"] = sequence_to_json_array(lists);
out["details"]["items_compiled"] = sequence_to_json_array(l.items);
out["details"]["plugins"] = nlohmann::json::array(); // always empty
}
void falco_engine::get_json_evt_types(
nlohmann::json& out,
const std::string& source,
libsinsp::filter::ast::expr* ast) const
{
// note: this duplicates part of the logic of evttype_index_ruleset,
// not good but it's our best option for now
if (source.empty() || source == falco_common::syscall_source)
{
auto evtcodes = libsinsp::filter::ast::ppm_event_codes(ast);
evtcodes.insert(ppm_event_code::PPME_ASYNCEVENT_E);
auto syscodes = libsinsp::filter::ast::ppm_sc_codes(ast);
auto syscodes_to_evt_names = libsinsp::events::sc_set_to_event_names(syscodes);
auto evtcodes_to_evt_names = libsinsp::events::event_set_to_names(evtcodes, false);
out = sequence_to_json_array(unordered_set_union(syscodes_to_evt_names, evtcodes_to_evt_names));
}
else
{
out = sequence_to_json_array(libsinsp::events::event_set_to_names(
{ppm_event_code::PPME_PLUGINEVENT_E, ppm_event_code::PPME_ASYNCEVENT_E}));
}
}
void falco_engine::get_json_used_plugins(
nlohmann::json& out,
const std::string& source,
const std::unordered_set<std::string>& evtnames,
const std::unordered_set<std::string>& fields,
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const
{
// note: condition and output fields may have an argument, so
// we need to isolate the field names
std::unordered_set<std::string> fieldnames;
for (const auto &f: fields)
{
auto argpos = f.find('[');
if (argpos != std::string::npos)
{
fieldnames.insert(f.substr(0, argpos));
}
else
{
fieldnames.insert(f);
}
}
std::unordered_set<std::string> used_plugins;
for (const auto& p : plugins)
{
bool used = false;
if (p->caps() & CAP_SOURCING)
{
// The rule's source is implemented by a plugin with event
// sourcing capability.
// Note: if Falco loads two plugins implementing the same source,
// they will both be included in the list.
if (!used && p->event_source() == source)
{
used_plugins.insert(p->name());
used = true;
}
}
if (!used && p->caps() & CAP_EXTRACTION)
{
// The rule uses a field implemented by a plugin with field
// extraction capability that is compatible with the rule's source.
// Note: here we're assuming that Falco will prevent loading
// plugins implementing fields with the same name for the same
// event source (implemented in init_inspectors app action).
if (sinsp_plugin::is_source_compatible(p->extract_event_sources(), source))
{
for (const auto &f : p->fields())
{
if (!used && fieldnames.find(f.m_name) != fieldnames.end())
{
used_plugins.insert(p->name());
used = true;
break;
}
}
}
}
if (!used && p->caps() & CAP_ASYNC)
{
// The rule matches an event type implemented by a plugin with
// async events capability that is compatible with the rule's source.
// Note: if Falco loads two plugins implementing async events with
// the same name, they will both be included in the list.
if (sinsp_plugin::is_source_compatible(p->async_event_sources(), source))
{
for (const auto &n : p->async_event_names())
{
if (!used && evtnames.find(n) != evtnames.end())
{
used_plugins.insert(p->name());
used = true;
break;
}
}
}
}
}
out = sequence_to_json_array(used_plugins);
}
void falco_engine::print_stats() const
{
@@ -799,6 +860,50 @@ bool falco_engine::is_source_valid(const std::string &source) const
return m_sources.at(source) != nullptr;
}
std::shared_ptr<gen_event_filter_factory> falco_engine::filter_factory_for_source(const std::string& source)
{
return find_source(source)->filter_factory;
}
std::shared_ptr<gen_event_filter_factory> falco_engine::filter_factory_for_source(std::size_t source_idx)
{
return find_source(source_idx)->filter_factory;
}
std::shared_ptr<gen_event_formatter_factory> falco_engine::formatter_factory_for_source(const std::string& source)
{
return find_source(source)->formatter_factory;
}
std::shared_ptr<gen_event_formatter_factory> falco_engine::formatter_factory_for_source(std::size_t source_idx)
{
return find_source(source_idx)->formatter_factory;
}
std::shared_ptr<filter_ruleset_factory> falco_engine::ruleset_factory_for_source(const std::string& source)
{
return find_source(source)->ruleset_factory;
}
std::shared_ptr<filter_ruleset_factory> falco_engine::ruleset_factory_for_source(std::size_t source_idx)
{
return find_source(source_idx)->ruleset_factory;
}
std::shared_ptr<filter_ruleset> falco_engine::ruleset_for_source(const std::string& source_name)
{
const falco_source *source = find_source(source_name);
return source->ruleset;
}
std::shared_ptr<filter_ruleset> falco_engine::ruleset_for_source(std::size_t source_idx)
{
const falco_source *source = find_source(source_idx);
return source->ruleset;
}
void falco_engine::read_file(const std::string& filename, std::string& contents)
{
std::ifstream is;
@@ -813,29 +918,6 @@ void falco_engine::read_file(const std::string& filename, std::string& contents)
std::istreambuf_iterator<char>());
}
void falco_engine::interpret_load_result(std::unique_ptr<load_result>& res,
const std::string& rules_filename,
const std::string& rules_content,
bool verbose)
{
falco::load_result::rules_contents_t rc = {{rules_filename, rules_content}};
if(!res->successful())
{
// The output here is always the full e.g. "verbose" output.
throw falco_exception(res->as_string(true, rc).c_str());
}
if(verbose && res->has_warnings())
{
// Here, verbose controls whether to additionally
// "log" e.g. print to stderr. What's logged is always
// non-verbose so it fits on a single line.
// todo(jasondellaluce): introduce a logging callback in Falco
fprintf(stderr, "%s\n", res->as_string(false, rc).c_str());
}
}
static bool check_plugin_requirement_alternatives(
const std::vector<falco_engine::plugin_version_requirement>& plugins,
const rule_loader::plugin_version_info::requirement_alternatives& alternatives,
@@ -849,14 +931,14 @@ static bool check_plugin_requirement_alternatives(
{
sinsp_version req_version(req.version);
sinsp_version plugin_version(plugin.version);
if(!plugin_version.m_valid)
if(!plugin_version.is_valid())
{
err = "Plugin '" + plugin.name
+ "' has invalid version string '"
+ plugin.version + "'";
return false;
}
if (!plugin_version.check(req_version))
if (!plugin_version.compatible_with(req_version))
{
err = "Plugin '" + plugin.name
+ "' version '" + plugin.version

View File

@@ -39,6 +39,8 @@ limitations under the License.
#include "falco_source.h"
#include "falco_load_result.h"
#include "filter_details_resolver.h"
#include "rule_loader_reader.h"
#include "rule_loader_compiler.h"
//
// This class acts as the primary interface between a program and the
@@ -56,22 +58,24 @@ public:
// and rules file format it supports. This version will change
// any time the code that handles rules files, expression
// fields, etc, changes.
static uint32_t engine_version();
static sinsp_version engine_version();
// Engine version used to be represented as a simple progressive
// number. With the new semver schema, the number now represents
// the semver minor number. This function converts the legacy version
// number to the new semver schema.
static inline sinsp_version get_implicit_version(uint32_t minor)
{
return rule_loader::reader::get_implicit_engine_version(minor);
}
// Print to stdout (using printf) a description of each field supported by this engine.
// If source is non-empty, only fields for the provided source are printed.
void list_fields(std::string &source, bool verbose, bool names_only, bool markdown) const;
//
// Load rules either directly or from a filename.
// Load rules and returns a result object.
//
void load_rules_file(const std::string &rules_filename, bool verbose, bool all_events);
void load_rules(const std::string &rules_content, bool verbose, bool all_events);
//
// Identical to above, but returns a result object instead of
// throwing exceptions on error.
std::unique_ptr<falco::load_result> load_rules_file(const std::string &rules_filename);
std::unique_ptr<falco::load_result> load_rules(const std::string &rules_content, const std::string &name);
//
@@ -85,15 +89,23 @@ public:
//
void enable_rule(const std::string &substring, bool enabled, const std::string &ruleset = s_default_ruleset);
// Same as above but providing a ruleset id instead
void enable_rule(const std::string &substring, bool enabled, const uint16_t ruleset_id);
// Like enable_rule, but the rule name must be an exact match.
void enable_rule_exact(const std::string &rule_name, bool enabled, const std::string &ruleset = s_default_ruleset);
// Same as above but providing a ruleset id instead
void enable_rule_exact(const std::string &rule_name, bool enabled, const uint16_t ruleset_id);
//
// Enable/Disable any rules with any of the provided tags (set, exact matches only)
//
void enable_rule_by_tag(const std::set<std::string> &tags, bool enabled, const std::string &ruleset = s_default_ruleset);
// Same as above but providing a ruleset id instead
void enable_rule_by_tag(const std::set<std::string> &tags, bool enabled, const uint16_t ruleset_id);
//
// Must be called after the engine has been configured and all rulesets
// have been loaded and enabled/disabled.
@@ -125,7 +137,7 @@ public:
// Print details on the given rule. If rule is NULL, print
// details on all rules.
//
void describe_rule(std::string *rule, bool json) const;
nlohmann::json describe_rule(std::string *rule, const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const;
//
// Print statistics on how many events matched each rule.
@@ -223,6 +235,31 @@ public:
// factory for this source.
bool is_source_valid(const std::string &source) const;
//
// Given a source, return a formatter factory that can create
// filters for events of that source.
//
std::shared_ptr<gen_event_filter_factory> filter_factory_for_source(const std::string& source);
std::shared_ptr<gen_event_filter_factory> filter_factory_for_source(std::size_t source_idx);
//
// Given a source, return a formatter factory that can create
// formatters for an event.
//
std::shared_ptr<gen_event_formatter_factory> formatter_factory_for_source(const std::string& source);
std::shared_ptr<gen_event_formatter_factory> formatter_factory_for_source(std::size_t source_idx);
//
// Given a source, return a ruleset factory that can create
// rulesets for that source.
//
std::shared_ptr<filter_ruleset_factory> ruleset_factory_for_source(const std::string& source);
std::shared_ptr<filter_ruleset_factory> ruleset_factory_for_source(std::size_t source_idx);
// Return the filter_ruleset used for a given source.
std::shared_ptr<filter_ruleset> ruleset_for_source(const std::string& source);
std::shared_ptr<filter_ruleset> ruleset_for_source(std::size_t source_idx);
//
// Given an event source and ruleset, fill in a bitset
// containing the event types for which this ruleset can run.
@@ -277,17 +314,46 @@ private:
// Throws falco_exception if the file can not be read
void read_file(const std::string& filename, std::string& contents);
// For load_rules methods that throw exceptions on error,
// interpret a load_result and throw an exception if needed.
void interpret_load_result(std::unique_ptr<falco::load_result>& res,
const std::string& rules_filename,
const std::string& rules_content,
bool verbose);
indexed_vector<falco_source> m_sources;
const falco_source* find_source(std::size_t index) const;
const falco_source* find_source(const std::string& name) const;
inline const falco_source* find_source(std::size_t index)
{
const falco_source *source;
if(index == m_syscall_source_idx)
{
if(m_syscall_source == NULL)
{
m_syscall_source = m_sources.at(m_syscall_source_idx);
if(!m_syscall_source)
{
throw falco_exception("Unknown event source index " + std::to_string(index));
}
}
source = m_syscall_source;
}
else
{
source = m_sources.at(index);
if(!source)
{
throw falco_exception("Unknown event source index " + std::to_string(index));
}
}
return source;
}
inline const falco_source* find_source(const std::string& name) const
{
auto ret = m_sources.at(name);
if(!ret)
{
throw falco_exception("Unknown event source " + name);
}
return ret;
}
// To allow the engine to be extremely fast for syscalls (can
// be > 1M events/sec), we save the syscall source/source_idx
@@ -303,18 +369,31 @@ private:
inline bool should_drop_evt() const;
// Retrieve json details from rules, macros, lists
void get_json_details(const falco_rule& r,
const rule_loader::rule_info& ri,
sinsp* insp,
Json::Value& rule) const;
void get_json_details(const rule_loader::macro_info& m,
Json::Value& macro) const;
void get_json_details(const rule_loader::list_info& l,
Json::Value& list) const;
void get_json_details(libsinsp::filter::ast::expr* ast,
Json::Value& output) const;
void get_json_evt_types(libsinsp::filter::ast::expr* ast,
Json::Value& output) const;
void get_json_details(
nlohmann::json& out,
const falco_rule& r,
const rule_loader::rule_info& info,
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const;
void get_json_details(
nlohmann::json& out,
const falco_macro& m,
const rule_loader::macro_info& info,
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const;
void get_json_details(
nlohmann::json& out,
const falco_list& l,
const rule_loader::list_info& info,
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const;
void get_json_evt_types(
nlohmann::json& out,
const std::string& source,
libsinsp::filter::ast::expr* ast) const;
void get_json_used_plugins(
nlohmann::json& out,
const std::string& source,
const std::unordered_set<std::string>& evttypes,
const std::unordered_set<std::string>& fields,
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const;
rule_loader::collector m_rule_collector;
indexed_vector<falco_rule> m_rules;
@@ -324,6 +403,8 @@ private:
std::map<std::string, uint16_t> m_known_rulesets;
falco_common::priority_type m_min_priority;
std::unique_ptr<rule_loader::compiler::compile_output> m_last_compile_output;
//
// Here's how the sampling ratio and multiplier influence
// whether or not an event is dropped in
@@ -353,4 +434,3 @@ private:
std::string m_extra;
bool m_replace_container_info;
};

View File

@@ -15,8 +15,18 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// The version of this Falco engine.
#define FALCO_ENGINE_VERSION (26)
#define __FALCO_ENGINE_STRINGIFY1(str) #str
#define __FALCO_ENGINE_STRINGIFY(str) __FALCO_ENGINE_STRINGIFY1(str)
// The version of this Falco engine
#define FALCO_ENGINE_VERSION_MAJOR 0
#define FALCO_ENGINE_VERSION_MINOR 31
#define FALCO_ENGINE_VERSION_PATCH 0
#define FALCO_ENGINE_VERSION \
__FALCO_ENGINE_STRINGIFY(FALCO_ENGINE_VERSION_MAJOR) "." \
__FALCO_ENGINE_STRINGIFY(FALCO_ENGINE_VERSION_MINOR) "." \
__FALCO_ENGINE_STRINGIFY(FALCO_ENGINE_VERSION_PATCH)
// This is the result of running the following command:
// FALCO="falco -c ./falco.yaml"
@@ -24,4 +34,4 @@ limitations under the License.
// 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 "98c6e665031b95c666a9ab02d5470e7008e8636bf02f4cc410912005b90dff5c"
#define FALCO_ENGINE_CHECKSUM "7c512927c89f594f024f2ff181077c780c4fe6e9dd4cee3f20a9ef208a356e4e"

View File

@@ -66,7 +66,8 @@ static const std::string warning_codes[] = {
"LOAD_UNKNOWN_FILTER",
"LOAD_UNUSED_MACRO",
"LOAD_UNUSED_LIST",
"LOAD_UNKNOWN_ITEM"
"LOAD_UNKNOWN_ITEM",
"LOAD_DEPRECATED_ITEM"
};
const std::string& falco::load_result::warning_code_str(warning_code wc)
@@ -81,7 +82,8 @@ static const std::string warning_strings[] = {
"Unknown field or event-type in condition or output",
"Unused macro",
"Unused list",
"Unknown rules file item"
"Unknown rules file item",
"Used deprecated item"
};
const std::string& falco::load_result::warning_str(warning_code wc)
@@ -96,7 +98,8 @@ static const std::string warning_descs[] = {
"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."
"An unknown top-level object is in the rules content. It will be ignored.",
"A deprecated item is employed by lists, macros, or rules."
};
const std::string& falco::load_result::warning_desc(warning_code wc)

View File

@@ -54,7 +54,8 @@ public:
LOAD_UNKNOWN_FILTER,
LOAD_UNUSED_MACRO,
LOAD_UNUSED_LIST,
LOAD_UNKNOWN_ITEM
LOAD_UNKNOWN_ITEM,
LOAD_DEPRECATED_ITEM
};
virtual ~load_result() = default;

View File

@@ -21,6 +21,46 @@ limitations under the License.
#include <string>
#include "falco_common.h"
#include <filter/ast.h>
/*!
\brief Represents a list in the Falco Engine.
The rule ID must be unique across all the lists loaded in the engine.
*/
struct falco_list
{
falco_list(): used(false), id(0) { }
falco_list(falco_list&&) = default;
falco_list& operator = (falco_list&&) = default;
falco_list(const falco_list&) = default;
falco_list& operator = (const falco_list&) = default;
~falco_list() = default;
bool used;
std::size_t id;
std::string name;
std::vector<std::string> items;
};
/*!
\brief Represents a macro in the Falco Engine.
The rule ID must be unique across all the macros loaded in the engine.
*/
struct falco_macro
{
falco_macro(): used(false), id(0) { }
falco_macro(falco_macro&&) = default;
falco_macro& operator = (falco_macro&&) = default;
falco_macro(const falco_macro&) = default;
falco_macro& operator = (const falco_macro&) = default;
~falco_macro() = default;
bool used;
std::size_t id;
std::string name;
std::shared_ptr<libsinsp::filter::ast::expr> condition;
};
/*!
\brief Represents a rule in the Falco Engine.
The rule ID must be unique across all the rules loaded in the engine.
@@ -32,6 +72,7 @@ struct falco_rule
falco_rule& operator = (falco_rule&&) = default;
falco_rule(const falco_rule&) = default;
falco_rule& operator = (const falco_rule&) = default;
~falco_rule() = default;
std::size_t id;
std::string source;
@@ -41,4 +82,5 @@ struct falco_rule
std::set<std::string> tags;
std::set<std::string> exception_fields;
falco_common::priority_type priority;
std::shared_ptr<libsinsp::filter::ast::expr> condition;
};

View File

@@ -22,7 +22,6 @@ limitations under the License.
#include "falco_utils.h"
#include "utils.h"
#include "banned.h" // This raises a compilation error when certain functions are used
#include <re2/re2.h>
@@ -160,6 +159,7 @@ void readfile(const std::string& filename, std::string& data)
return;
}
namespace network
{
bool is_unix_scheme(const std::string& url)

View File

@@ -19,22 +19,36 @@ limitations under the License.
using namespace libsinsp::filter;
std::string get_field_name(const std::string& name, const std::string& arg)
{
std::string fld = name;
if (!arg.empty())
{
fld += "[" + arg + "]";
}
return fld;
}
void filter_details::reset()
{
fields.clear();
macros.clear();
operators.clear();
lists.clear();
evtnames.clear();
}
void filter_details_resolver::run(ast::expr* filter, filter_details& details)
{
visitor v(details);
// note: we may have ASTs composed on only one macro ref
v.m_expect_macro = true;
filter->accept(&v);
}
void filter_details_resolver::visitor::visit(ast::and_expr* e)
{
m_expect_macro = false;
for(size_t i = 0; i < e->children.size(); i++)
{
m_expect_macro = true;
@@ -45,6 +59,7 @@ void filter_details_resolver::visitor::visit(ast::and_expr* e)
void filter_details_resolver::visitor::visit(ast::or_expr* e)
{
m_expect_macro = false;
for(size_t i = 0; i < e->children.size(); i++)
{
m_expect_macro = true;
@@ -70,35 +85,50 @@ void filter_details_resolver::visitor::visit(ast::list_expr* e)
}
}
}
if (m_expect_evtname)
{
for(const auto& item : e->values)
{
if(m_details.known_lists.find(item) == m_details.known_lists.end())
{
m_details.evtnames.insert(item);
}
}
}
}
void filter_details_resolver::visitor::visit(ast::binary_check_expr* e)
{
m_expect_macro = false;
m_details.fields.insert(e->field);
m_details.fields.insert(get_field_name(e->field, e->arg));
m_details.operators.insert(e->op);
m_expect_list = true;
m_expect_evtname = e->field == "evt.type" || e->field == "evt.asynctype";
e->value->accept(this);
m_expect_evtname = false;
m_expect_list = false;
}
void filter_details_resolver::visitor::visit(ast::unary_check_expr* e)
{
m_expect_macro = false;
m_details.fields.insert(e->field);
m_details.fields.insert(get_field_name(e->field, e->arg));
m_details.operators.insert(e->op);
}
void filter_details_resolver::visitor::visit(ast::value_expr* e)
{
if(m_expect_macro)
if (m_expect_macro)
{
auto it = m_details.known_macros.find(e->value);
if(it == m_details.known_macros.end())
if(m_details.known_macros.find(e->value) != m_details.known_macros.end())
{
return;
m_details.macros.insert(e->value);
}
m_details.macros.insert(e->value);
// todo(jasondellaluce): should we throw an error if we
// encounter an unknown macro?
}
else if (m_expect_evtname)
{
m_details.evtnames.insert(e->value);
}
}

View File

@@ -22,17 +22,18 @@ limitations under the License.
#include <unordered_set>
#include <unordered_map>
struct filter_details
struct filter_details
{
// input macros and lists
std::unordered_set<std::string> known_macros;
std::unordered_set<std::string> known_lists;
// output details
std::unordered_set<std::string> fields;
std::unordered_set<std::string> macros;
std::unordered_set<std::string> operators;
std::unordered_set<std::string> lists;
std::unordered_set<std::string> evtnames;
void reset();
};
@@ -46,24 +47,23 @@ public:
/*!
\brief Visits a filter AST and stores details about macros, lists,
fields and operators used.
\param filter The filter AST to be processed.
\param details Helper structure used to state known macros and
\param filter The filter AST to be processed.
\param details Helper structure used to state known macros and
lists on input, and to store all the retrieved details as output.
*/
void run(libsinsp::filter::ast::expr* filter,
filter_details& details);
private:
struct visitor : public libsinsp::filter::ast::expr_visitor
{
visitor(filter_details& details) :
visitor(filter_details& details) :
m_details(details),
m_expect_list(false),
m_expect_macro(false) {}
m_expect_macro(false),
m_expect_evtname(false) {}
visitor(visitor&&) = default;
visitor& operator = (visitor&&) = default;
visitor(const visitor&) = delete;
visitor& operator = (const visitor&) = delete;
void visit(libsinsp::filter::ast::and_expr* e) override;
void visit(libsinsp::filter::ast::or_expr* e) override;
@@ -76,5 +76,6 @@ private:
filter_details& m_details;
bool m_expect_list;
bool m_expect_macro;
bool m_expect_evtname;
};
};

View File

@@ -61,7 +61,7 @@ class filter_macro_resolver
/*!
\brief used in get_{resolved,unknown}_macros and get_errors
to represent an identifier/string value along with an AST position.
to represent an identifier/string value along with an AST position.
*/
typedef std::pair<std::string,libsinsp::filter::ast::pos_info> value_info;
@@ -103,10 +103,6 @@ class filter_macro_resolver
m_unknown_macros(unknown_macros),
m_resolved_macros(resolved_macros),
m_macros(macros) {}
visitor(visitor&&) = default;
visitor& operator = (visitor&&) = default;
visitor(const visitor&) = delete;
visitor& operator = (const visitor&) = delete;
std::vector<std::string> m_macros_path;
std::unique_ptr<libsinsp::filter::ast::expr> m_node_substitute;

View File

@@ -19,7 +19,6 @@ limitations under the License.
#include "formats.h"
#include "falco_engine.h"
#include "banned.h" // This raises a compilation error when certain functions are used
falco_formats::falco_formats(std::shared_ptr<const falco_engine> engine,
bool json_include_output_property,

File diff suppressed because it is too large Load Diff

View File

@@ -1,512 +0,0 @@
// SPDX-License-Identifier: Apache-2.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.
*/
#pragma once
#include <memory>
#include <list>
#include <map>
#include <string>
#include <vector>
#include <set>
#include <utility>
#include <nlohmann/json.hpp>
#include "falco_common.h"
#include "prefix_search.h"
#include <sinsp.h>
class json_event : public gen_event
{
public:
json_event();
virtual ~json_event();
void set_jevt(nlohmann::json &evt, uint64_t ts);
const nlohmann::json &jevt();
uint64_t get_ts() const;
inline uint16_t get_source() const
{
return ESRC_K8S_AUDIT;
}
inline uint16_t get_type() const
{
// All k8s audit events have the single tag "1". - see falco_engine::process_k8s_audit_event
return ppm_event_code::PPME_PLUGINEVENT_E;
}
protected:
nlohmann::json m_jevt;
uint64_t m_event_ts;
};
namespace falco_k8s_audit {
//
// Given a raw json object, return a list of k8s audit event
// objects that represent the object. This method handles
// things such as EventList splitting.
//
// Returns true if the json object was recognized as a k8s
// audit event(s), false otherwise.
//
bool parse_k8s_audit_json(nlohmann::json &j, std::list<json_event> &evts, bool top=true);
};
// A class representing an extracted value or a value on the rhs of a
// filter_check. This intentionally doesn't use the same types as
// ppm_events_public.h to take advantage of actual classes instead of
// lower-level pointers pointing to syscall events and to allow for
// efficient set comparisons.
class json_event_value
{
public:
enum param_type {
JT_STRING,
JT_INT64,
JT_INT64_PAIR
};
json_event_value();
json_event_value(const std::string &val);
json_event_value(int64_t val);
virtual ~json_event_value();
param_type ptype() const;
std::string as_string() const;
bool operator==(const json_event_value &val) const;
bool operator!=(const json_event_value &val) const;
bool operator<(const json_event_value &val) const;
bool operator>(const json_event_value &val) const;
// Only meaningful for string types
bool startswith(const json_event_value &val) const;
bool contains(const json_event_value &val) const;
private:
param_type m_type;
static bool parse_as_pair_int64(std::pair<int64_t,int64_t> &pairval, const std::string &val);
static bool parse_as_int64(int64_t &intval, const std::string &val);
// The number of possible types is small so far, so sticking
// with separate vars
std::string m_stringval;
int64_t m_intval;
std::pair<int64_t,int64_t> m_pairval;
};
class json_event_filter_check : public gen_event_filter_check
{
public:
static std::string no_value;
enum index_mode
{
IDX_REQUIRED,
IDX_ALLOWED,
IDX_NONE
};
static std::vector<std::string> s_index_mode_strs;
enum index_type
{
IDX_KEY,
IDX_NUMERIC
};
static std::vector<std::string> s_index_type_strs;
// A struct describing a single filtercheck field ("ka.user")
struct field_info
{
std::string m_name;
std::string m_desc;
index_mode m_idx_mode;
index_type m_idx_type;
bool m_uses_paths;
// The variants allow for brace-initialization either
// with just the name/desc or additionally with index
// information
field_info();
field_info(std::string name, std::string desc);
field_info(std::string name, std::string desc, index_mode mode);
field_info(std::string name, std::string desc, index_mode mode, index_type itype);
field_info(std::string name, std::string desc, index_mode mode, index_type itype, bool uses_paths);
virtual ~field_info();
};
// A struct describing a group of filtercheck fields ("ka")
struct check_info
{
std::string m_name;
std::string m_shortdesc;
std::string m_desc;
std::list<field_info> m_fields;
};
json_event_filter_check();
virtual ~json_event_filter_check() = 0;
virtual int32_t parse_field_name(const char *str, bool alloc_state, bool needed_for_filtering);
void add_filter_value(const char *str, uint32_t len, uint32_t i = 0);
bool compare(gen_event *evt);
// This is adapted to support the new extract() method signature that
// supports extracting list of values, however json_evt was implemented
// to support this feature in the first place through the
// extracted_values_t structure. As such, for now this is only used for
// signature compliance, and always pushes a single value. The value pushed
// in the vector is a a const extracted_values_t* that points to the
// internal m_evalues. This is a temporary workaround to sync with the
// latest falcosecurity/libs development without re-designing the whole K8S
// support, which will eventually be refactored as a plugin in the future anyway.
bool extract(gen_event *evt, std::vector<extract_value_t>& values, bool sanitize_strings = true) final;
const std::string &field();
const std::string &idx();
// The combined size of the field, index, and surrounding
// brackets (e.g. ka.image[foo])
size_t parsed_size();
virtual const check_info &get_info() const = 0;
//
// Allocate a new check of the same type. Must be overridden.
//
virtual json_event_filter_check *allocate_new() = 0;
// Subclasses or extraction functions can call this method to add each extracted value.
void add_extracted_value(const std::string &val);
void add_extracted_value_num(int64_t val);
// After calling extract, you can call extracted_values to get
// the values extracted from an event.
typedef std::vector<json_event_value> values_t;
const values_t &extracted_values();
protected:
// Subclasses can override this method, calling
// add_extracted_value to add extracted values.
virtual bool extract_values(json_event *jevt);
static std::string json_as_string(const nlohmann::json &j);
// Subclasses can define field names that act as aliases for
// specific json pointer expressions e.g. ka.user ==
// jevt.value[/user/username]. This struct represents one of
// those aliases.
// An alias might define an alternative function to extract
// values instead of using a json pointer. An example is
// ka.uri.param, which parses the query string to extract
// key=value parameters.
typedef std::function<bool (const nlohmann::json &, json_event_filter_check &jchk)> extract_t;
struct alias
{
// The variants allow for brace-initialization either
// with just the pointer list or with a custom
// extraction function.
alias();
alias(std::list<nlohmann::json::json_pointer> ptrs);
alias(extract_t extract);
virtual ~alias();
// A json pointer used to extract a referenced value
// from a json object. The pointers are applied in
// order. After applying a pointer, if the resulting
// object is an array, each array member is considered
// for subsequent json pointers.
//
// This allows for "plucking" items out of an array
// selected by an earlier json pointer.
std::list<nlohmann::json::json_pointer> m_jptrs;
extract_t m_extract;
};
// This map defines the aliases defined by this filter check
// class.
//
// The version of parse_field_name in this base class will
// check a field specification against all the aliases.
virtual const std::unordered_map<std::string, alias> &get_aliases() const = 0;
//check_info m_info;
// The actual field name parsed in parse_field_name.
std::string m_field;
// The field name itself might include an index component
// e.g. ka.value[idx]. This holds the index.
std::string m_idx;
private:
typedef std::set<json_event_value> values_set_t;
typedef std::pair<values_t, values_set_t> extracted_values_t;
// The default extraction function uses the list of pointers
// in m_jptrs. Iterates over array elements between pointers if
// found.
bool def_extract(const nlohmann::json &j,
const std::list<nlohmann::json::json_pointer> &ptrs,
std::list<nlohmann::json::json_pointer>::iterator it);
// The actual json pointer value to use to extract from
// events. See alias struct for usage.
std::list<nlohmann::json::json_pointer> m_jptrs;
// The extraction function to use. May not be defined, in which
// case the default function is used.
extract_t m_extract;
// All values specified on the right hand side of the operator
// e.g. "ka.ns in ("one","two","three"), m_values has ("one",
// "two", "three")
values_set_t m_values;
// All values extracted from the object by the field e.g. for
// a field ka.req.container.image returns all container images
// for all pods within a request.
extracted_values_t m_evalues;
// If true, this filtercheck works on paths, which enables
// some extra bookkeeping to allow for path prefix searches.
bool m_uses_paths = false;
path_prefix_search m_prefix_search;
};
class jevt_filter_check : public json_event_filter_check
{
public:
jevt_filter_check();
virtual ~jevt_filter_check();
int32_t parse_field_name(const char* str, bool alloc_state, bool needed_for_filtering) final;
json_event_filter_check *allocate_new() override;
const check_info &get_info() const override;
protected:
bool extract_values(json_event *jevt) final;
const std::unordered_map<std::string, alias> &get_aliases() const override
{
static std::unordered_map<std::string, alias> a;
return a;
};
private:
// When the field is jevt_value, a json pointer representing
// the index in m_idx
nlohmann::json::json_pointer m_idx_ptr;
static std::string s_jevt_time_field;
static std::string s_jevt_time_iso_8601_field;
static std::string s_jevt_rawtime_field;
static std::string s_jevt_obj_field;
static std::string s_jevt_value_field;
};
class k8s_audit_filter_check : public json_event_filter_check
{
public:
k8s_audit_filter_check();
virtual ~k8s_audit_filter_check();
json_event_filter_check *allocate_new() override;
const check_info &get_info() const override;
const std::unordered_map<std::string, alias> &get_aliases() const override;
// Extract all images/image repositories from the provided containers
static bool extract_images(const nlohmann::json &j,
json_event_filter_check &jchk);
// Extract all query parameters
static bool extract_query_param(const nlohmann::json &j,
json_event_filter_check &jchk);
// Extract some property from the set of rules in the request object
static bool extract_rule_attrs(const nlohmann::json &j,
json_event_filter_check &jchk);
// Determine if the provided path matches any volumes host path.
static bool check_volumes_hostpath(const nlohmann::json &j,
json_event_filter_check &jchk);
// Extract the volume types from volumes in the request object
static bool extract_volume_types(const nlohmann::json &j,
json_event_filter_check &jchk);
// Extract all hostPort values from containers in the request object
static bool extract_host_port(const nlohmann::json &j,
json_event_filter_check &jchk);
// Using both the pod and container security contexts, extract
// the uid/gid that will be used for each container.
static bool extract_effective_run_as(const nlohmann::json &j,
json_event_filter_check &jchk);
// These are only used for compatibility with older rules files
// Always return the string "N/A"
static bool always_return_na(const nlohmann::json &j,
json_event_filter_check &jchk);
// Return true if any container has privileged=true
static bool extract_any_privileged(const nlohmann::json &j,
json_event_filter_check &jchk);
};
class json_event_filter : public sinsp_filter
{
public:
json_event_filter();
virtual ~json_event_filter();
std::string m_rule;
uint32_t m_rule_idx;
std::set<std::string> m_tags;
};
class json_event_filter_factory : public gen_event_filter_factory
{
public:
json_event_filter_factory();
virtual ~json_event_filter_factory();
// Create a new filter
gen_event_filter *new_filter();
// Create a new filter_check
gen_event_filter_check *new_filtercheck(const char *fldname);
// All defined field names
std::list<gen_event_filter_factory::filter_fieldclass_info> get_fields();
private:
std::list<std::shared_ptr<json_event_filter_check>> m_defined_checks;
std::list<json_event_filter_check::check_info> m_info;
};
class json_event_formatter : public gen_event_formatter
{
public:
json_event_formatter(std::shared_ptr<gen_event_filter_factory> factory);
virtual ~json_event_formatter();
void set_format(output_format of, const std::string &format) override;
bool tostring(gen_event *evt, std::string &output) override;
bool tostring_withformat(gen_event *evt, std::string &output, gen_event_formatter::output_format of) override;
bool get_field_values(gen_event *evt, std::map<std::string, std::string> &fields) override;
void get_field_names(std::vector<std::string> &fields) override
{
throw falco_exception("json_event_formatter::get_field_names operation not supported");
}
output_format get_output_format() override;
std::string tojson(json_event *ev);
// Split the format string into a list of tuples, broken at
// output fields, where each tuple is either a block of text
// from the original format string, or a field value/pair from
// the original format string.
//
// For example, given a format string "some output
// (%proc.name)", this will fill in resolved with 3 tuples:
// - ["", "some output ("]
// - ["proc.name", "nginx"]
// - ["", ")"]
//
// This can be used either to return a resolved output string
// or a map of field name/value pairs.
void resolve_format(json_event *ev, std::list<std::pair<std::string, std::string>> &resolved);
private:
void parse_format();
// A format token is either a combination of a filtercheck
// name (ka.value) and filtercheck object as key, or an empty
// key and a NULL filtercheck object, combined with a value (
//
// For example, given a format string:
// "The value is %ka.value today"
// The tokens would be:
// [("The value is ", NULL), ("ka.value", <an object>), " today", NULL)]
struct fmt_token
{
std::string text;
std::shared_ptr<json_event_filter_check> check;
};
gen_event_formatter::output_format m_output_format;
// The original format string
std::string m_format;
// The chunks that make up the format string, in order, broken
// up between text chunks and filterchecks.
std::list<fmt_token> m_tokens;
// All the filterchecks required to resolve tokens in the format string
std::shared_ptr<gen_event_filter_factory> m_json_factory;
};
class json_event_formatter_factory : public gen_event_formatter_factory
{
public:
json_event_formatter_factory(std::shared_ptr<gen_event_filter_factory> factory);
virtual ~json_event_formatter_factory();
void set_output_format(gen_event_formatter::output_format of) override;
std::shared_ptr<gen_event_formatter> create_formatter(const std::string &format) override;
protected:
// Maps from output string to formatter
std::map<std::string, std::shared_ptr<gen_event_formatter>> m_formatters;
gen_event_formatter::output_format m_output_format;
// All the filterchecks required to resolve tokens in the format string
std::shared_ptr<gen_event_filter_factory> m_json_factory;
};

View File

@@ -41,7 +41,8 @@ static const std::string item_type_strings[] = {
"condition expression",
"rule output",
"rule output expression",
"rule priority"
"rule priority",
"overrides"
};
const std::string& rule_loader::context::item_type_as_string(enum item_type it)
@@ -517,7 +518,7 @@ const nlohmann::json& rule_loader::result::as_json(const rules_contents_t& conte
}
rule_loader::engine_version_info::engine_version_info(context &ctx)
: ctx(ctx), version(0)
: ctx(ctx)
{
}
@@ -532,12 +533,12 @@ rule_loader::plugin_version_info::plugin_version_info(context &ctx)
}
rule_loader::list_info::list_info(context &ctx)
: ctx(ctx), used(false), index(0), visibility(0)
: ctx(ctx), index(0), visibility(0)
{
}
rule_loader::macro_info::macro_info(context &ctx)
: ctx(ctx), cond_ctx(ctx), used(false), index(0), visibility(0)
: ctx(ctx), cond_ctx(ctx), index(0), visibility(0)
{
}
@@ -553,6 +554,11 @@ rule_loader::rule_info::rule_info(context &ctx)
{
}
rule_loader::rule_update_info::rule_update_info(context &ctx)
: ctx(ctx), cond_ctx(ctx)
{
}
rule_loader::rule_load_exception::rule_load_exception(falco::load_result::error_code ec, const std::string& msg, const context& ctx)
: ec(ec), msg(msg), ctx(ctx)
{
@@ -562,10 +568,8 @@ rule_loader::rule_load_exception::~rule_load_exception()
{
}
const char* rule_loader::rule_load_exception::what()
const char* rule_loader::rule_load_exception::what() const noexcept
{
errstr = falco::load_result::error_code_str(ec) + ": "
+ msg.c_str();
return errstr.c_str();
// const + noexcept: can't use functions that change the object or throw
return msg.c_str();
}

View File

@@ -19,11 +19,13 @@ limitations under the License.
#include <string>
#include <vector>
#include <optional>
#include <yaml-cpp/yaml.h>
#include <nlohmann/json.hpp>
#include "falco_source.h"
#include "falco_load_result.h"
#include "indexed_vector.h"
#include "version.h"
namespace rule_loader
{
@@ -55,7 +57,8 @@ namespace rule_loader
CONDITION_EXPRESSION,
RULE_OUTPUT,
RULE_OUTPUT_EXPRESSION,
RULE_PRIORITY
RULE_PRIORITY,
OVERRIDE
};
static const std::string& item_type_as_string(enum item_type it);
@@ -208,18 +211,12 @@ namespace rule_loader
public:
rule_load_exception(falco::load_result::error_code ec, const std::string& msg, const context& ctx);
virtual ~rule_load_exception();
rule_load_exception(rule_load_exception&&) = default;
rule_load_exception& operator = (rule_load_exception&&) = default;
rule_load_exception(const rule_load_exception&) = default;
rule_load_exception& operator = (const rule_load_exception&) = default;
const char* what();
const char* what() const noexcept override;
falco::load_result::error_code ec;
std::string msg;
context ctx;
std::string errstr;
};
/*!
@@ -273,24 +270,20 @@ namespace rule_loader
const indexed_vector<falco_source>& srcs,
const std::string& name)
: content(cont), sources(srcs), name(name),
default_ruleset_id(0), replace_output_container_info(false),
min_priority(falco_common::PRIORITY_DEBUG)
output_extra(), replace_output_container_info(false)
{
res.reset(new result(name));
}
configuration(configuration&&) = default;
configuration& operator = (configuration&&) = default;
configuration(const configuration&) = delete;
configuration& operator = (const configuration&) = delete;
// inputs
const std::string& content;
const indexed_vector<falco_source>& sources;
std::string name;
std::unique_ptr<result> res;
std::string output_extra;
uint16_t default_ruleset_id;
bool replace_output_container_info;
falco_common::priority_type min_priority;
// outputs
std::unique_ptr<result> res;
};
/*!
@@ -298,7 +291,7 @@ namespace rule_loader
*/
struct engine_version_info
{
engine_version_info() : ctx("no-filename-given"), version(0) { };
engine_version_info() : ctx("no-filename-given"), version("0.0.0") { };
engine_version_info(context &ctx);
~engine_version_info() = default;
engine_version_info(engine_version_info&&) = default;
@@ -307,7 +300,7 @@ namespace rule_loader
engine_version_info& operator = (const engine_version_info&) = default;
context ctx;
uint32_t version;
sinsp_version version;
};
/*!
@@ -359,7 +352,6 @@ namespace rule_loader
list_info& operator = (const list_info&) = default;
context ctx;
bool used;
size_t index;
size_t visibility;
std::string name;
@@ -380,12 +372,10 @@ namespace rule_loader
context ctx;
context cond_ctx;
bool used;
size_t index;
size_t visibility;
std::string name;
std::string cond;
std::shared_ptr<libsinsp::filter::ast::expr> cond_ast;
};
/*!
@@ -463,4 +453,38 @@ namespace rule_loader
bool warn_evttypes;
bool skip_if_unknown_filter;
};
/*!
\brief Represents infos about a rule update (append or replace) request
*/
struct rule_update_info
{
rule_update_info(context &ctx);
~rule_update_info() = default;
rule_update_info(rule_update_info&&) = default;
rule_update_info& operator = (rule_update_info&&) = default;
rule_update_info(const rule_update_info&) = default;
rule_update_info& operator = (const rule_update_info&) = default;
bool has_any_value()
{
return cond.has_value() || output.has_value() || desc.has_value() || tags.has_value() ||
exceptions.has_value() || priority.has_value() || enabled.has_value() ||
warn_evttypes.has_value() || skip_if_unknown_filter.has_value();
}
context ctx;
context cond_ctx;
std::string name;
std::optional<std::string> cond;
std::optional<std::string> output;
std::optional<std::string> desc;
std::optional<std::set<std::string>> tags;
std::optional<std::vector<rule_exception_info>> exceptions;
std::optional<falco_common::priority_type> priority;
std::optional<bool> enabled;
std::optional<bool> warn_evttypes;
std::optional<bool> skip_if_unknown_filter;
};
};

View File

@@ -20,6 +20,7 @@ limitations under the License.
#include "falco_engine.h"
#include "rule_loader_collector.h"
#include "rule_loading_messages.h"
#define THROW(cond, err, ctx) { if ((cond)) { throw rule_loader::rule_load_exception(falco::load_result::LOAD_ERR_VALIDATE, (err), (ctx)); } }
@@ -48,8 +49,14 @@ static inline void define_info(indexed_vector<T>& infos, T& info, uint32_t id)
}
}
template <typename T>
static inline void append_info(T* prev, T& info, uint32_t id)
template <typename T, typename U>
static inline void append_info(T* prev, U& info, uint32_t id)
{
prev->visibility = id;
}
template <typename T, typename U>
static inline void replace_info(T* prev, U& info, uint32_t id)
{
prev->visibility = id;
}
@@ -146,9 +153,11 @@ const indexed_vector<rule_loader::rule_info>& rule_loader::collector::rules() co
void rule_loader::collector::define(configuration& cfg, engine_version_info& info)
{
auto v = falco_engine::engine_version();
THROW(v < info.version, "Rules require engine version "
+ std::to_string(info.version) + ", but engine version is " + std::to_string(v),
THROW(!v.compatible_with(info.version), "Rules require engine version "
+ info.version.as_string() + ", but engine version is " + v.as_string(),
info.ctx);
// Store max required_engine_version
if(m_required_engine_version.version < info.version)
{
m_required_engine_version = info;
@@ -161,7 +170,7 @@ void rule_loader::collector::define(configuration& cfg, plugin_version_info& inf
for (const auto& req : info.alternatives)
{
sinsp_version plugin_version(req.version);
THROW(!plugin_version.m_valid,
THROW(!plugin_version.is_valid(),
"Invalid required version '" + req.version
+ "' for plugin '" + req.name + "'",
info.ctx);
@@ -182,9 +191,7 @@ void rule_loader::collector::define(configuration& cfg, list_info& info)
void rule_loader::collector::append(configuration& cfg, list_info& info)
{
auto prev = m_list_infos.at(info.name);
THROW(!prev,
"List has 'append' key but no list by that name already exists",
info.ctx);
THROW(!prev, ERROR_NO_PREVIOUS_LIST, info.ctx);
prev->items.insert(prev->items.end(), info.items.begin(), info.items.end());
append_info(prev, info, m_cur_index++);
}
@@ -197,9 +204,7 @@ void rule_loader::collector::define(configuration& cfg, macro_info& info)
void rule_loader::collector::append(configuration& cfg, macro_info& info)
{
auto prev = m_macro_infos.at(info.name);
THROW(!prev,
"Macro has 'append' key but no macro by that name already exists",
info.ctx);
THROW(!prev, ERROR_NO_PREVIOUS_MACRO, info.ctx);
prev->cond += " ";
prev->cond += info.cond;
append_info(prev, info, m_cur_index++);
@@ -231,15 +236,14 @@ void rule_loader::collector::define(configuration& cfg, rule_info& info)
define_info(m_rule_infos, info, m_cur_index++);
}
void rule_loader::collector::append(configuration& cfg, rule_info& info)
void rule_loader::collector::append(configuration& cfg, rule_update_info& info)
{
auto prev = m_rule_infos.at(info.name);
THROW(!prev,
"Rule has 'append' key but no rule by that name already exists",
info.ctx);
THROW(info.cond.empty() && info.exceptions.empty(),
THROW(!prev, ERROR_NO_PREVIOUS_RULE_APPEND, info.ctx);
THROW(!info.has_any_value(),
"Appended rule must have exceptions or condition property",
// "Appended rule must have at least one field that can be appended to", // TODO replace with this and update testing
info.ctx);
// note: source can be nullptr in case we've collected a
@@ -254,43 +258,136 @@ void rule_loader::collector::append(configuration& cfg, rule_info& info)
info.ctx);
}
if (!info.cond.empty())
if (info.cond.has_value() && !info.cond->empty())
{
prev->cond += " ";
prev->cond += info.cond;
prev->cond += *info.cond;
}
for (auto &ex : info.exceptions)
if (info.output.has_value() && !info.output->empty())
{
auto prev_ex = find_if(prev->exceptions.begin(), prev->exceptions.end(),
[&ex](const rule_loader::rule_exception_info& i)
{ return i.name == ex.name; });
if (prev_ex == prev->exceptions.end())
prev->output += " ";
prev->output += *info.output;
}
if (info.desc.has_value() && !info.desc->empty())
{
prev->desc += " ";
prev->desc += *info.desc;
}
if (info.tags.has_value())
{
for (auto &tag: *info.tags)
{
THROW(!ex.fields.is_valid(),
"Rule exception must have fields property with a list of fields",
ex.ctx);
THROW(ex.values.empty(),
"Rule exception must have values property with a list of values",
ex.ctx);
validate_exception_info(source, ex);
prev->exceptions.push_back(ex);
}
else
{
THROW(ex.fields.is_valid(),
"Can not append exception fields to existing exception, only values",
ex.ctx);
THROW(ex.comps.is_valid(),
"Can not append exception comps to existing exception, only values",
ex.ctx);
prev_ex->values.insert(
prev_ex->values.end(), ex.values.begin(), ex.values.end());
prev->tags.insert(tag);
}
}
if (info.exceptions.has_value())
{
for (auto &ex : *info.exceptions)
{
auto prev_ex = find_if(prev->exceptions.begin(), prev->exceptions.end(),
[&ex](const rule_loader::rule_exception_info& i)
{ return i.name == ex.name; });
if (prev_ex == prev->exceptions.end())
{
THROW(!ex.fields.is_valid(),
"Rule exception must have fields property with a list of fields",
ex.ctx);
THROW(ex.values.empty(),
"Rule exception must have values property with a list of values",
ex.ctx);
validate_exception_info(source, ex);
prev->exceptions.push_back(ex);
}
else
{
THROW(ex.fields.is_valid(),
"Can not append exception fields to existing exception, only values",
ex.ctx);
THROW(ex.comps.is_valid(),
"Can not append exception comps to existing exception, only values",
ex.ctx);
prev_ex->values.insert(
prev_ex->values.end(), ex.values.begin(), ex.values.end());
}
}
}
append_info(prev, info, m_cur_index++);
}
void rule_loader::collector::selective_replace(configuration& cfg, rule_update_info& info)
{
auto prev = m_rule_infos.at(info.name);
THROW(!prev, ERROR_NO_PREVIOUS_RULE_REPLACE, info.ctx);
THROW(!info.has_any_value(),
"The rule must have at least one field that can be replaced",
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.has_value())
{
prev->cond = *info.cond;
}
if (info.output.has_value())
{
prev->output = *info.output;
}
if (info.desc.has_value())
{
prev->desc = *info.desc;
}
if (info.tags.has_value())
{
prev->tags = *info.tags;
}
if (info.exceptions.has_value())
{
prev->exceptions = *info.exceptions;
}
if (info.priority.has_value())
{
prev->priority = *info.priority;
}
if (info.enabled.has_value())
{
prev->enabled = *info.enabled;
}
if (info.warn_evttypes.has_value())
{
prev->warn_evttypes = *info.warn_evttypes;
}
if (info.skip_if_unknown_filter.has_value())
{
prev->skip_if_unknown_filter = *info.skip_if_unknown_filter;
}
replace_info(prev, info, m_cur_index++);
}
void rule_loader::collector::enable(configuration& cfg, rule_info& info)
{
auto prev = m_rule_infos.at(info.name);

View File

@@ -85,13 +85,18 @@ public:
*/
virtual void append(configuration& cfg, list_info& info);
virtual void append(configuration& cfg, macro_info& info);
virtual void append(configuration& cfg, rule_info& info);
virtual void append(configuration& cfg, rule_update_info& info);
/*!
\brief Updates the 'enabled' flag of an existing definition
*/
virtual void enable(configuration& cfg, rule_info& info);
/*!
\brief Selectively replaces some fields of an existing definition
*/
virtual void selective_replace(configuration& cfg, rule_update_info& info);
private:
uint32_t m_cur_index;
indexed_vector<rule_info> m_rule_infos;

View File

@@ -50,12 +50,6 @@ static void paren_item(std::string& e)
}
}
static inline bool is_operator_defined(const std::string& op)
{
auto ops = libsinsp::filter::parser::supported_operators();
return find(ops.begin(), ops.end(), op) != ops.end();
}
static inline bool is_operator_for_list(const std::string& op)
{
auto ops = libsinsp::filter::parser::supported_operators(true);
@@ -83,12 +77,12 @@ static void build_rule_exception_infos(
std::string& condition)
{
std::string tmp;
for (auto &ex : exceptions)
for (const auto &ex : exceptions)
{
std::string icond;
if(!ex.fields.is_list)
{
for (auto &val : ex.values)
for (const auto &val : ex.values)
{
THROW(val.is_list,
"Expected values array to contain a list of strings",
@@ -107,7 +101,7 @@ static void build_rule_exception_infos(
else
{
icond = "(";
for (auto &values : ex.values)
for (const auto &values : ex.values)
{
THROW(ex.fields.items.size() != values.items.size(),
"Fields and values lists must have equal length",
@@ -116,13 +110,13 @@ static void build_rule_exception_infos(
icond += "(";
uint32_t k = 0;
std::string istr;
for (auto &field : ex.fields.items)
for (const auto &field : ex.fields.items)
{
icond += k == 0 ? "" : " and ";
if (values.items[k].is_list)
{
istr = "(";
for (auto &v : values.items[k].items)
for (const auto &v : values.items[k].items)
{
tmp = v.item;
quote_item(tmp);
@@ -160,11 +154,34 @@ static void build_rule_exception_infos(
}
}
static inline rule_loader::list_info* list_info_from_name(
const rule_loader::collector& c, const std::string& name)
{
auto ret = c.lists().at(name);
if (!ret)
{
throw falco_exception("can't find internal list info at name: " + name);
}
return ret;
}
static inline rule_loader::macro_info* macro_info_from_name(
const rule_loader::collector& c, const std::string& name)
{
auto ret = c.macros().at(name);
if (!ret)
{
throw falco_exception("can't find internal macro info at name: " + name);
}
return ret;
}
// todo(jasondellaluce): this breaks string escaping in lists
static bool resolve_list(std::string& cnd, const rule_loader::list_info& list)
static bool resolve_list(std::string& cnd, const falco_list& list)
{
static std::string blanks = " \t\n\r";
static std::string delims = blanks + "(),=";
std::string tmp;
std::string new_cnd;
size_t start, end;
bool used = false;
@@ -190,13 +207,15 @@ static bool resolve_list(std::string& cnd, const rule_loader::list_info& list)
}
// create substitution string by concatenating all values
std::string sub = "";
for (auto &v : list.items)
for (const auto &v : list.items)
{
if (!sub.empty())
{
sub += ", ";
}
sub += v;
tmp = v;
quote_item(tmp);
sub += tmp;
}
// if substituted list is empty, we need to
// remove a comma from the left or the right
@@ -232,18 +251,20 @@ static bool resolve_list(std::string& cnd, const rule_loader::list_info& list)
}
static void resolve_macros(
indexed_vector<rule_loader::macro_info>& macros,
const indexed_vector<rule_loader::macro_info>& infos,
indexed_vector<falco_macro>& macros,
std::shared_ptr<ast::expr>& ast,
const std::string& condition,
uint32_t visibility,
const rule_loader::context &ctx)
{
filter_macro_resolver macro_resolver;
for (auto &m : macros)
for (const auto &m : infos)
{
if (m.index < visibility)
{
macro_resolver.set_macro(m.name, m.cond_ast);
auto macro = macros.at(m.name);
macro_resolver.set_macro(m.name, macro->condition);
}
}
macro_resolver.run(ast);
@@ -263,7 +284,7 @@ static void resolve_macros(
THROW(true, errmsg, cond_ctx);
}
for (auto &it : macro_resolver.get_resolved_macros())
for (const auto &it : macro_resolver.get_resolved_macros())
{
macros.at(it.first)->used = true;
}
@@ -272,7 +293,7 @@ static void resolve_macros(
// note: there is no visibility order between filter conditions and lists
static std::shared_ptr<ast::expr> parse_condition(
std::string condition,
indexed_vector<rule_loader::list_info>& lists,
indexed_vector<falco_list>& lists,
const rule_loader::context &ctx)
{
for (auto &l : lists)
@@ -319,37 +340,35 @@ static void apply_output_substitutions(
void rule_loader::compiler::compile_list_infos(
configuration& cfg,
const collector& col,
indexed_vector<list_info>& out) const
indexed_vector<falco_list>& out) const
{
std::string tmp;
std::vector<std::string> used;
for (auto &list : col.lists())
std::list<std::string> used;
falco_list v;
for (const auto &list : col.lists())
{
list_info v = list;
v.name = list.name;
v.items.clear();
for (auto &item : list.items)
for (const auto &item : list.items)
{
const auto ref = col.lists().at(item);
if (ref && ref->index < list.visibility)
{
used.push_back(ref->name);
for (auto val : ref->items)
for (const auto &val : ref->items)
{
quote_item(val);
v.items.push_back(val);
}
}
else
{
tmp = item;
quote_item(tmp);
v.items.push_back(tmp);
v.items.push_back(item);
}
}
v.used = false;
out.insert(v, v.name);
auto list_id = out.insert(v, v.name);
out.at(list_id)->id = list_id;
}
for (auto &v : used)
for (const auto &v : used)
{
out.at(v)->used = true;
}
@@ -359,20 +378,23 @@ void rule_loader::compiler::compile_list_infos(
void rule_loader::compiler::compile_macros_infos(
configuration& cfg,
const collector& col,
indexed_vector<list_info>& lists,
indexed_vector<macro_info>& out) const
indexed_vector<falco_list>& lists,
indexed_vector<falco_macro>& out) const
{
for (auto &m : col.macros())
for (const auto &m : col.macros())
{
macro_info entry = m;
entry.cond_ast = parse_condition(m.cond, lists, m.cond_ctx);
falco_macro entry;
entry.name = m.name;
entry.condition = parse_condition(m.cond, lists, m.cond_ctx);
entry.used = false;
out.insert(entry, m.name);
auto macro_id = out.insert(entry, m.name);
out.at(macro_id)->id = macro_id;
}
for (auto &m : out)
{
resolve_macros(out, m.cond_ast, m.cond, m.visibility, m.ctx);
auto info = macro_info_from_name(col, m.name);
resolve_macros(col.macros(), out, m.condition, info->cond, info->visibility, info->ctx);
}
}
@@ -386,14 +408,14 @@ static bool err_is_unknown_type_or_field(const std::string& err)
void rule_loader::compiler::compile_rule_infos(
configuration& cfg,
const collector& col,
indexed_vector<list_info>& lists,
indexed_vector<macro_info>& macros,
indexed_vector<falco_list>& lists,
indexed_vector<falco_macro>& macros,
indexed_vector<falco_rule>& out) const
{
std::string err, condition;
std::set<falco::load_result::load_result::warning_code> warn_codes;
filter_warning_resolver warn_resolver;
for (auto &r : col.rules())
for (const auto &r : col.rules())
{
// skip the rule if it has an unknown source
if (r.unknown_source)
@@ -401,12 +423,6 @@ void rule_loader::compiler::compile_rule_infos(
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);
THROW(!source,
@@ -423,14 +439,14 @@ void rule_loader::compiler::compile_rule_infos(
build_rule_exception_infos(
r.exceptions, rule.exception_fields, condition);
}
auto ast = parse_condition(condition, lists, r.cond_ctx);
resolve_macros(macros, ast, condition, MAX_VISIBILITY, r.ctx);
rule.condition = parse_condition(condition, lists, r.cond_ctx);
resolve_macros(col.macros(), macros, rule.condition, condition, MAX_VISIBILITY, r.ctx);
// check for warnings in the filtering condition
warn_codes.clear();
if (warn_resolver.run(ast.get(), warn_codes))
if (warn_resolver.run(rule.condition.get(), warn_codes))
{
for (auto &w : warn_codes)
for (const auto &w : warn_codes)
{
cfg.res->add_warning(w, "", r.ctx);
}
@@ -443,8 +459,11 @@ void rule_loader::compiler::compile_rule_infos(
apply_output_substitutions(cfg, rule.output);
}
// validate the rule's output
if(!is_format_valid(*cfg.sources.at(r.source), rule.output, err))
{
// skip the rule silently if skip_if_unknown_filter is true and
// we encountered some specific kind of errors
if (err_is_unknown_type_or_field(err) && r.skip_if_unknown_filter)
{
cfg.res->add_warning(
@@ -459,30 +478,18 @@ void rule_loader::compiler::compile_rule_infos(
r.output_ctx);
}
// construct rule definition and compile it to a filter
rule.name = r.name;
rule.source = r.source;
rule.description = r.desc;
rule.priority = r.priority;
rule.tags = r.tags;
auto rule_id = out.insert(rule, rule.name);
out.at(rule_id)->id = rule_id;
// This also compiles the filter, and might throw a
// falco_exception with details on the compilation
// failure.
sinsp_filter_compiler compiler(cfg.sources.at(r.source)->filter_factory, ast.get());
try {
std::shared_ptr<gen_event_filter> filter(compiler.compile());
source->ruleset->add(*out.at(rule_id), filter, ast);
// validate the rule's condition: we compile it into a sinsp filter
// on-the-fly and we throw an exception with details on failure
sinsp_filter_compiler compiler(cfg.sources.at(r.source)->filter_factory, rule.condition.get());
try
{
std::shared_ptr<sinsp_filter> sfPtr(compiler.compile());
}
catch (const sinsp_exception& e)
{
// Allow errors containing "nonexistent field" if
// skip_if_unknown_filter is true
// skip the rule silently if skip_if_unknown_filter is true and
// we encountered some specific kind of errors
std::string err = e.what();
if (err_is_unknown_type_or_field(err) && r.skip_if_unknown_filter)
{
cfg.res->add_warning(
@@ -491,7 +498,6 @@ void rule_loader::compiler::compile_rule_infos(
r.cond_ctx);
continue;
}
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,
@@ -499,20 +505,10 @@ void rule_loader::compiler::compile_rule_infos(
ctx);
}
// By default rules are enabled/disabled for the default ruleset
if(r.enabled)
{
source->ruleset->enable(rule.name, true, cfg.default_ruleset_id);
}
else
{
source->ruleset->disable(rule.name, true, cfg.default_ruleset_id);
}
// populate set of event types and emit an special warning
if(rule.source == falco_common::syscall_source)
if(r.source == falco_common::syscall_source)
{
auto evttypes = libsinsp::filter::ast::ppm_event_codes(ast.get());
auto evttypes = libsinsp::filter::ast::ppm_event_codes(rule.condition.get());
if ((evttypes.empty() || evttypes.size() > 100) && r.warn_evttypes)
{
cfg.res->add_warning(
@@ -521,23 +517,29 @@ void rule_loader::compiler::compile_rule_infos(
r.ctx);
}
}
// finalize the rule definition and add it to output
rule.name = r.name;
rule.source = r.source;
rule.description = r.desc;
rule.priority = r.priority;
rule.tags = r.tags;
auto rule_id = out.insert(rule, rule.name);
out.at(rule_id)->id = rule_id;
}
}
void rule_loader::compiler::compile(
configuration& cfg,
const collector& col,
indexed_vector<falco_rule>& out) const
compile_output& out) const
{
indexed_vector<list_info> lists;
indexed_vector<macro_info> macros;
// expand all lists, macros, and rules
try
{
compile_list_infos(cfg, col, lists);
compile_macros_infos(cfg, col, lists, macros);
compile_rule_infos(cfg, col, lists, macros, out);
compile_list_infos(cfg, col, out.lists);
compile_macros_infos(cfg, col, out.lists, out.macros);
compile_rule_infos(cfg, col, out.lists, out.macros, out.rules);
}
catch(rule_load_exception &e)
{
@@ -546,24 +548,24 @@ void rule_loader::compiler::compile(
}
// print info on any dangling lists or macros that were not used anywhere
for (auto &m : macros)
for (const auto &m : out.macros)
{
if (!m.used)
{
cfg.res->add_warning(
falco::load_result::load_result::LOAD_UNUSED_MACRO,
"Macro not referred to by any other rule/macro",
m.ctx);
macro_info_from_name(col, m.name)->ctx);
}
}
for (auto &l : lists)
for (const auto &l : out.lists)
{
if (!l.used)
{
cfg.res->add_warning(
falco::load_result::LOAD_UNUSED_LIST,
"List not referred to by any other rule/macro",
l.ctx);
list_info_from_name(col, l.name)->ctx);
}
}
}

View File

@@ -31,6 +31,23 @@ namespace rule_loader
class compiler
{
public:
/*!
\brief The output of a compilation.
*/
struct compile_output
{
compile_output() = default;
virtual ~compile_output() = default;
compile_output(compile_output&&) = default;
compile_output& operator = (compile_output&&) = default;
compile_output(const compile_output&) = default;
compile_output& operator = (const compile_output&) = default;
indexed_vector<falco_list> lists;
indexed_vector<falco_macro> macros;
indexed_vector<falco_rule> rules;
};
compiler() = default;
virtual ~compiler() = default;
compiler(compiler&&) = default;
@@ -44,25 +61,25 @@ public:
virtual void compile(
configuration& cfg,
const collector& col,
indexed_vector<falco_rule>& out) const;
compile_output& out) const;
private:
void compile_list_infos(
configuration& cfg,
const collector& col,
indexed_vector<list_info>& out) const;
indexed_vector<falco_list>& out) const;
void compile_macros_infos(
configuration& cfg,
const collector& col,
indexed_vector<list_info>& lists,
indexed_vector<macro_info>& out) const;
indexed_vector<falco_list>& lists,
indexed_vector<falco_macro>& out) const;
void compile_rule_infos(
configuration& cfg,
const collector& col,
indexed_vector<list_info>& lists,
indexed_vector<macro_info>& macros,
indexed_vector<falco_list>& lists,
indexed_vector<falco_macro>& macros,
indexed_vector<falco_rule>& out) const;
};

View File

@@ -17,8 +17,12 @@ limitations under the License.
#include <string>
#include <vector>
#include <set>
#include <sstream>
#include "rule_loader_reader.h"
#include "falco_engine_version.h"
#include "rule_loading_messages.h"
#define THROW(cond, err, ctx) { if ((cond)) { throw rule_loader::rule_load_exception(falco::load_result::LOAD_ERR_YAML_VALIDATE, (err), (ctx)); } }
@@ -43,6 +47,14 @@ static void decode_val_generic(const YAML::Node& item, const char *key, T& out,
THROW(!YAML::convert<T>::decode(val, out), "Can't decode YAML scalar value", valctx);
}
template <typename T>
static void decode_val_generic(const YAML::Node& item, const char *key, std::optional<T>& out, const rule_loader::context& ctx, bool optional)
{
T decoded;
decode_val_generic(item, key, decoded, ctx, optional);
out = decoded;
}
template <typename T>
static void decode_val(const YAML::Node& item, const char *key, T& out, const rule_loader::context& ctx)
{
@@ -113,6 +125,73 @@ static void decode_tags(const YAML::Node& item, std::set<T>& out,
decode_seq(item, "tags", inserter, ctx, optional);
}
template <typename T>
static void decode_tags(const YAML::Node& item, std::optional<std::set<T>>& out,
const rule_loader::context& ctx)
{
std::set<T> decoded;
decode_tags(item, decoded, ctx);
out = decoded;
}
static void decode_overrides(const YAML::Node& item,
std::set<std::string>& overridable_append,
std::set<std::string>& overridable_replace,
std::set<std::string>& out_append,
std::set<std::string>& out_replace,
const rule_loader::context& ctx)
{
const YAML::Node& val = item["override"];
if(!val.IsDefined())
{
return;
}
rule_loader::context overridectx(item, rule_loader::context::OVERRIDE, "", ctx);
for(YAML::const_iterator it=val.begin();it!=val.end();++it)
{
std::string key = it->first.as<std::string>();
std::string operation = it->second.as<std::string>();
bool is_overridable_append = overridable_append.find(it->first.as<std::string>()) != overridable_append.end();
bool is_overridable_replace = overridable_replace.find(it->first.as<std::string>()) != overridable_replace.end();
if (operation == "append")
{
rule_loader::context keyctx(it->first, rule_loader::context::OVERRIDE, key, overridectx);
THROW(!is_overridable_append, std::string("Key '") + key + std::string("' cannot be appended to, use 'replace' instead"), keyctx);
out_append.insert(key);
}
else if (operation == "replace")
{
rule_loader::context keyctx(it->first, rule_loader::context::OVERRIDE, key, overridectx);
THROW(!is_overridable_replace, std::string("Key '") + key + std::string("' cannot be replaced"), keyctx);
out_replace.insert(key);
}
else
{
rule_loader::context operationctx(it->second, rule_loader::context::VALUE_FOR, key, overridectx);
std::stringstream err_ss;
err_ss << "Invalid override operation for key '" << key << "': '" << operation << "'. "
<< "Allowed values are: ";
if (is_overridable_append)
{
err_ss << "append ";
}
if (is_overridable_replace)
{
err_ss << "replace ";
}
THROW(true, err_ss.str(), operationctx);
}
}
}
// Don't call this directly, call decode_exception_{fields,comps,values} instead
static void decode_exception_info_entry(
const YAML::Node& item,
@@ -185,7 +264,7 @@ static void decode_exception_values(
static void read_rule_exceptions(
const YAML::Node& item,
rule_loader::rule_info& v,
std::vector<rule_loader::rule_exception_info>& exceptions,
const rule_loader::context& parent,
bool append)
{
@@ -237,10 +316,36 @@ static void read_rule_exceptions(
v_ex.values.push_back(v_ex_val);
}
}
v.exceptions.push_back(v_ex);
exceptions.push_back(v_ex);
}
}
static void read_rule_exceptions(
const YAML::Node& item,
std::optional<std::vector<rule_loader::rule_exception_info>>& exceptions,
const rule_loader::context& parent,
bool append)
{
std::vector<rule_loader::rule_exception_info> decoded;
read_rule_exceptions(item, decoded, parent, append);
exceptions = decoded;
}
inline static bool check_update_expected(std::set<std::string>& expected_keys, const std::set<std::string>& overrides, const std::string& override_type, const std::string& key, const rule_loader::context& ctx)
{
if (overrides.find(key) == overrides.end())
{
return false;
}
THROW(expected_keys.find(key) == expected_keys.end(),
std::string("An ") + override_type + " override for '" + key + "' was specified but '" + key + "' is not defined", ctx);
expected_keys.erase(key);
return true;
}
static void read_item(
rule_loader::configuration& cfg,
rule_loader::collector& collector,
@@ -255,8 +360,27 @@ static void read_item(
{
rule_loader::context ctx(item, rule_loader::context::REQUIRED_ENGINE_VERSION, "", parent);
rule_loader::engine_version_info v(ctx);
try
{
// Convert convert to an uint (more restrictive than converting to a string)
uint32_t ver;
decode_val(item, "required_engine_version", ver, ctx);
// Build proper semver representation
v.version = rule_loader::reader::get_implicit_engine_version(ver);
}
catch(std::exception& e)
{
// Convert to string
std::string ver;
decode_val(item, "required_engine_version", ver, ctx);
v.version = sinsp_version(ver);
THROW(!v.version.is_valid(), "Unable to parse engine version '" + ver + "' as a semver string. Expected \"x.y.z\" semver format.", ctx);
}
decode_val(item, "required_engine_version", v.version, ctx);
collector.define(cfg, v);
}
else if(item["required_plugin_versions"].IsDefined())
@@ -316,6 +440,21 @@ static void read_item(
decode_items(item, v.items, ctx);
decode_optional_val(item, "append", append, ctx);
if(append)
{
cfg.res->add_warning(falco::load_result::LOAD_DEPRECATED_ITEM, WARNING_APPEND, ctx);
}
std::set<std::string> override_append, override_replace;
std::set<std::string> overridable {"items"};
decode_overrides(item, overridable, overridable, override_append, override_replace, ctx);
bool has_overrides = !override_append.empty() || !override_replace.empty();
THROW(append && has_overrides, ERROR_OVERRIDE_APPEND, ctx);
// Since a list only has items, if we have chosen to append them we can append the entire object
// otherwise we just want to redefine the list.
append |= override_append.find("items") != override_append.end();
if(append)
{
@@ -344,6 +483,21 @@ static void read_item(
v.cond_ctx = rule_loader::context(item["condition"], rule_loader::context::MACRO_CONDITION, "", ctx);
decode_optional_val(item, "append", append, ctx);
if(append)
{
cfg.res->add_warning(falco::load_result::LOAD_DEPRECATED_ITEM, WARNING_APPEND, ctx);
}
std::set<std::string> override_append, override_replace;
std::set<std::string> overridable {"condition"};
decode_overrides(item, overridable, overridable, override_append, override_replace, ctx);
bool has_overrides = !override_append.empty() || !override_replace.empty();
THROW((append && has_overrides), ERROR_OVERRIDE_APPEND, ctx);
// Since a macro only has a condition, if we have chosen to append to it we can append the entire object
// otherwise we just want to redefine the macro.
append |= override_append.find("condition") != override_append.end();
if(append)
{
@@ -363,28 +517,172 @@ static void read_item(
decode_val(item, "rule", name, tmp);
rule_loader::context ctx(item, rule_loader::context::RULE, name, parent);
rule_loader::rule_info v(ctx);
v.name = name;
bool append = false;
v.enabled = true;
v.warn_evttypes = true;
v.skip_if_unknown_filter = false;
decode_optional_val(item, "append", append, ctx);
if(append)
bool has_append_flag = false;
decode_optional_val(item, "append", has_append_flag, ctx);
if(has_append_flag)
{
decode_optional_val(item, "condition", v.cond, ctx);
cfg.res->add_warning(falco::load_result::LOAD_DEPRECATED_ITEM, WARNING_APPEND, ctx);
}
std::set<std::string> override_append, override_replace;
std::set<std::string> overridable_append {"condition", "output", "desc", "tags", "exceptions"};
std::set<std::string> overridable_replace {
"condition", "output", "desc", "priority", "tags", "exceptions", "enabled", "warn_evttypes", "skip-if-unknown-filter"};
decode_overrides(item, overridable_append, overridable_replace, override_append, override_replace, ctx);
bool has_overrides_append = !override_append.empty();
bool has_overrides_replace = !override_replace.empty();
bool has_overrides = has_overrides_append || has_overrides_replace;
THROW((has_append_flag && has_overrides), ERROR_OVERRIDE_APPEND, ctx);
if(has_overrides)
{
std::set<std::string> expected_keys;
for (auto& key : overridable_append)
{
if (item[key].IsDefined())
{
expected_keys.insert(key);
}
}
for (auto& key : overridable_replace)
{
if (item[key].IsDefined())
{
expected_keys.insert(key);
}
}
// expected_keys is (appendable U replaceable) ^ (defined)
if (has_overrides_append)
{
rule_loader::rule_update_info v(ctx);
v.name = name;
if (check_update_expected(expected_keys, override_append, "append", "condition", ctx))
{
decode_val(item, "condition", v.cond, ctx);
}
if (check_update_expected(expected_keys, override_append, "append", "exceptions", ctx))
{
read_rule_exceptions(item, v.exceptions, ctx, true);
}
if (check_update_expected(expected_keys, override_append, "append", "output", ctx))
{
decode_val(item, "output", v.output, ctx);
}
if (check_update_expected(expected_keys, override_append, "append", "desc", ctx))
{
decode_val(item, "desc", v.desc, ctx);
}
if (check_update_expected(expected_keys, override_append, "append", "tags", ctx))
{
decode_tags(item, v.tags, ctx);
}
collector.append(cfg, v);
}
if (has_overrides_replace)
{
rule_loader::rule_update_info v(ctx);
v.name = name;
if (check_update_expected(expected_keys, override_replace, "replace", "condition", ctx))
{
decode_val(item, "condition", v.cond, ctx);
}
if (check_update_expected(expected_keys, override_replace, "replace", "exceptions", ctx))
{
read_rule_exceptions(item, v.exceptions, ctx, true);
}
if (check_update_expected(expected_keys, override_replace, "replace", "output", ctx))
{
decode_val(item, "output", v.output, ctx);
}
if (check_update_expected(expected_keys, override_replace, "replace", "desc", ctx))
{
decode_val(item, "desc", v.desc, ctx);
}
if (check_update_expected(expected_keys, override_replace, "replace", "tags", ctx))
{
decode_tags(item, v.tags, ctx);
}
if (check_update_expected(expected_keys, override_replace, "replace", "priority", ctx))
{
std::string priority;
decode_val(item, "priority", priority, ctx);
rule_loader::context prictx(item["priority"], rule_loader::context::RULE_PRIORITY, "", ctx);
falco_common::priority_type parsed_priority;
THROW(!falco_common::parse_priority(priority, parsed_priority), "Invalid priority", prictx);
v.priority = parsed_priority;
}
if (check_update_expected(expected_keys, override_replace, "replace", "enabled", ctx))
{
decode_val(item, "enabled", v.enabled, ctx);
}
if (check_update_expected(expected_keys, override_replace, "replace", "warn_evttypes", ctx))
{
decode_val(item, "warn_evttypes", v.warn_evttypes, ctx);
}
if (check_update_expected(expected_keys, override_replace, "replace", "skip-if-unknown-filter", ctx))
{
decode_val(item, "skip-if-unknown-filter", v.skip_if_unknown_filter, ctx);
}
collector.selective_replace(cfg, v);
}
// if any expected key has not been defined throw an error
for (auto &key : expected_keys) {
rule_loader::context keyctx(item[key], rule_loader::context::OVERRIDE, key, ctx);
THROW(true, "Unexpected key '" + key + "': no corresponding entry under 'override' is defined.", keyctx);
}
}
else if(has_append_flag)
{
rule_loader::rule_update_info v(ctx);
v.name = name;
if(item["condition"].IsDefined())
{
v.cond_ctx = rule_loader::context(item["condition"], rule_loader::context::RULE_CONDITION, "", ctx);
decode_val(item, "condition", v.cond, ctx);
}
read_rule_exceptions(item, v, ctx, append);
if(item["exceptions"].IsDefined())
{
read_rule_exceptions(item, v.exceptions, ctx, true);
}
// TODO restore this error and update testing
//THROW((!v.cond.has_value() && !v.exceptions.has_value()),
// "Appended rule must have exceptions or condition property",
// v.ctx);
collector.append(cfg, v);
}
else
{
rule_loader::rule_info v(ctx);
v.name = name;
v.enabled = true;
v.warn_evttypes = true;
v.skip_if_unknown_filter = false;
// If the rule does *not* have any of
// condition/output/desc/priority, it *must*
// have an enabled property. Use the enabled
@@ -396,6 +694,7 @@ static void read_item(
!item["priority"].IsDefined())
{
decode_val(item, "enabled", v.enabled, ctx);
cfg.res->add_warning(falco::load_result::LOAD_DEPRECATED_ITEM, WARNING_ENABLED, ctx);
collector.enable(cfg, v);
}
else
@@ -422,7 +721,7 @@ static void read_item(
decode_optional_val(item, "warn_evttypes", v.warn_evttypes, ctx);
decode_optional_val(item, "skip-if-unknown-filter", v.skip_if_unknown_filter, ctx);
decode_tags(item, v.tags, ctx);
read_rule_exceptions(item, v, ctx, append);
read_rule_exceptions(item, v.exceptions, ctx, has_append_flag);
collector.define(cfg, v);
}
}

View File

@@ -19,6 +19,9 @@ limitations under the License.
#include "rule_loader.h"
#include "rule_loader_collector.h"
#include "logger.h"
#include "version.h"
#include "falco_engine_version.h"
namespace rule_loader
{
@@ -41,6 +44,19 @@ public:
thew new definitions
*/
virtual bool read(configuration& cfg, collector& loader);
/*!
\brief Engine version used to be represented as a simple progressive
number. With the new semver schema, the number now represents
the semver minor number. This function converts the legacy version
number to the new semver schema.
*/
static inline sinsp_version get_implicit_engine_version(uint32_t minor)
{
return sinsp_version(std::to_string(FALCO_ENGINE_VERSION_MAJOR) + "."
+ std::to_string(minor) + "."
+ std::to_string(FALCO_ENGINE_VERSION_PATCH));
}
};
}; // namespace rule_loader

View File

@@ -0,0 +1,23 @@
#pragma once
////////////////
// Warnings
////////////////
#define WARNING_APPEND "'append' key is deprecated. Add an 'append' entry (e.g. 'condition: append') under 'override' instead."
#define WARNING_ENABLED "The standalone 'enabled' key usage is deprecated. The correct approach requires also a 'replace' entry under the 'override' key (i.e. 'enabled: replace')."
////////////////
// Errors
////////////////
#define ERROR_OVERRIDE_APPEND "Keys 'override' and 'append: true' cannot be used together. Add an 'append' entry (e.g. 'condition: append') under 'override' instead."
#define ERROR_NO_PREVIOUS_MACRO "Macro uses 'append' or 'override.condition: append' but no macro by that name already exists"
#define ERROR_NO_PREVIOUS_LIST "List uses 'append' or 'override.items: append' but no list by that name already exists"
#define ERROR_NO_PREVIOUS_RULE_APPEND "Rule uses 'append' or 'override.<key>: append' but no rule by that name already exists"
#define ERROR_NO_PREVIOUS_RULE_REPLACE "An 'override.<key>: replace' to a rule was requested but no rule by that name already exists"

View File

@@ -35,10 +35,6 @@ class stats_manager
public:
stats_manager();
virtual ~stats_manager();
stats_manager(stats_manager&&) = default;
stats_manager& operator = (stats_manager&&) = default;
stats_manager(const stats_manager&) = default;
stats_manager& operator = (const stats_manager&) = default;
/*!
\brief Erases the internal state and statistics data

View File

@@ -26,7 +26,6 @@ set(
app/actions/pidfile.cpp
app/actions/init_falco_engine.cpp
app/actions/init_inspectors.cpp
app/actions/init_clients.cpp
app/actions/init_outputs.cpp
app/actions/list_fields.cpp
app/actions/list_plugins.cpp
@@ -37,6 +36,7 @@ set(
app/actions/print_generated_gvisor_config.cpp
app/actions/print_help.cpp
app/actions/print_ignored_events.cpp
app/actions/print_kernel_version.cpp
app/actions/print_plugin_info.cpp
app/actions/print_support.cpp
app/actions/print_syscall_events.cpp
@@ -53,9 +53,7 @@ set(
logger.cpp
falco_outputs.cpp
outputs_file.cpp
outputs_program.cpp
outputs_stdout.cpp
outputs_syslog.cpp
event_drops.cpp
stats_writer.cpp
versions_info.cpp
@@ -90,6 +88,14 @@ if(USE_BUNDLED_DEPS)
list(APPEND FALCO_DEPENDENCIES yamlcpp)
endif()
if(NOT WIN32)
list(
APPEND FALCO_SOURCES
outputs_program.cpp
outputs_syslog.cpp
)
endif()
if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT MINIMAL_BUILD)
list(
APPEND FALCO_SOURCES
@@ -214,12 +220,16 @@ if(MUSL_OPTIMIZED_BUILD AND CMAKE_BUILD_TYPE STREQUAL "release")
)
endif()
if (NOT EMSCRIPTEN)
install(TARGETS falco RUNTIME DESTINATION ${FALCO_BIN_DIR} COMPONENT "${FALCO_COMPONENT_NAME}")
if (EMSCRIPTEN)
install(FILES
"$<TARGET_FILE_DIR:falco>/falco.js"
"$<TARGET_FILE_DIR:falco>/falco.wasm"
DESTINATION ${FALCO_BIN_DIR}
COMPONENT "${FALCO_COMPONENT_NAME}")
elseif (WIN32)
install(TARGETS falco
DESTINATION bin
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}")
install(TARGETS falco RUNTIME DESTINATION ${FALCO_BIN_DIR} COMPONENT "${FALCO_COMPONENT_NAME}")
endif()

View File

@@ -30,7 +30,6 @@ 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 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);
falco::app::run_result init_outputs(falco::app::state& s);
@@ -42,6 +41,7 @@ falco::app::run_result load_rules_files(falco::app::state& s);
falco::app::run_result print_generated_gvisor_config(falco::app::state& s);
falco::app::run_result print_help(falco::app::state& s);
falco::app::run_result print_ignored_events(falco::app::state& s);
falco::app::run_result print_kernel_version(falco::app::state& s);
falco::app::run_result print_page_size(falco::app::state& s);
falco::app::run_result print_plugin_info(falco::app::state& s);
falco::app::run_result print_support(falco::app::state& s);

View File

@@ -69,7 +69,7 @@ static void select_event_set(falco::app::state& s, const libsinsp::events::set<p
auto rules_names = libsinsp::events::sc_set_to_event_names(rules_sc_set);
if (!rules_sc_set.empty())
{
falco_logger::log(LOG_DEBUG, "(" + std::to_string(rules_names.size())
falco_logger::log(falco_logger::level::DEBUG, "(" + std::to_string(rules_names.size())
+ ") syscalls in rules: " + concat_set_in_order(rules_names) + "\n");
}
@@ -100,14 +100,14 @@ static void select_event_set(falco::app::state& s, const libsinsp::events::set<p
// we re-transform from sc_set to names to make
// sure that bad user inputs are ignored
falco_logger::log(LOG_DEBUG, "+(" + std::to_string(user_positive_sc_set_names.size())
falco_logger::log(falco_logger::level::DEBUG, "+(" + std::to_string(user_positive_sc_set_names.size())
+ ") syscalls added (base_syscalls override): "
+ concat_set_in_order(user_positive_sc_set_names) + "\n");
}
auto invalid_positive_sc_set_names = unordered_set_difference(user_positive_names, user_positive_sc_set_names);
if (!invalid_positive_sc_set_names.empty())
{
falco_logger::log(LOG_WARNING, "Invalid (positive) syscall names: warning (base_syscalls override): "
falco_logger::log(falco_logger::level::WARNING, "Invalid (positive) syscall names: warning (base_syscalls override): "
+ concat_set_in_order(invalid_positive_sc_set_names));
}
@@ -136,14 +136,14 @@ static void select_event_set(falco::app::state& s, const libsinsp::events::set<p
// we re-transform from sc_set to names to make
// sure that bad user inputs are ignored
falco_logger::log(LOG_DEBUG, "-(" + std::to_string(user_negative_sc_set_names.size())
falco_logger::log(falco_logger::level::DEBUG, "-(" + std::to_string(user_negative_sc_set_names.size())
+ ") syscalls removed (base_syscalls override): "
+ concat_set_in_order(user_negative_sc_set_names) + "\n");
}
auto invalid_negative_sc_set_names = unordered_set_difference(user_negative_names, user_negative_sc_set_names);
if (!invalid_negative_sc_set_names.empty())
{
falco_logger::log(LOG_WARNING, "Invalid (negative) syscall names: warning (base_syscalls override): "
falco_logger::log(falco_logger::level::WARNING, "Invalid (negative) syscall names: warning (base_syscalls override): "
+ concat_set_in_order(invalid_negative_sc_set_names));
}
@@ -154,7 +154,7 @@ static void select_event_set(falco::app::state& s, const libsinsp::events::set<p
if (!non_rules_sc_set.empty() && user_positive_sc_set.empty())
{
auto non_rules_sc_set_names = libsinsp::events::sc_set_to_event_names(non_rules_sc_set);
falco_logger::log(LOG_DEBUG, "+(" + std::to_string(non_rules_sc_set_names.size())
falco_logger::log(falco_logger::level::DEBUG, "+(" + std::to_string(non_rules_sc_set_names.size())
+ ") syscalls (Falco's state engine set of syscalls): "
+ concat_set_in_order(non_rules_sc_set_names) + "\n");
}
@@ -172,7 +172,7 @@ static void select_event_set(falco::app::state& s, const libsinsp::events::set<p
if (!erased_sc_set.empty())
{
auto erased_sc_set_names = libsinsp::events::sc_set_to_event_names(erased_sc_set);
falco_logger::log(LOG_DEBUG, "-(" + std::to_string(erased_sc_set_names.size())
falco_logger::log(falco_logger::level::DEBUG, "-(" + std::to_string(erased_sc_set_names.size())
+ ") ignored syscalls (-> activate via `-A` flag): "
+ concat_set_in_order(erased_sc_set_names) + "\n");
}
@@ -192,7 +192,7 @@ static void select_event_set(falco::app::state& s, const libsinsp::events::set<p
if (!repaired_sc_set.empty())
{
auto repaired_sc_set_names = libsinsp::events::sc_set_to_event_names(repaired_sc_set);
falco_logger::log(LOG_INFO, "+(" + std::to_string(repaired_sc_set_names.size())
falco_logger::log(falco_logger::level::INFO, "+(" + std::to_string(repaired_sc_set_names.size())
+ ") repaired syscalls: " + concat_set_in_order(repaired_sc_set_names) + "\n");
}
}
@@ -207,7 +207,7 @@ static void select_event_set(falco::app::state& s, const libsinsp::events::set<p
if (!s.selected_sc_set.empty())
{
auto selected_sc_set_names = libsinsp::events::sc_set_to_event_names(s.selected_sc_set);
falco_logger::log(LOG_DEBUG, "(" + std::to_string(selected_sc_set_names.size())
falco_logger::log(falco_logger::level::DEBUG, "(" + std::to_string(selected_sc_set_names.size())
+ ") syscalls selected in total (final set): "
+ concat_set_in_order(selected_sc_set_names) + "\n");
}

View File

@@ -23,7 +23,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)
if(!s.is_modern_ebpf())
{
return run_result::ok();
}
@@ -34,10 +34,10 @@ falco::app::run_result falco::app::actions::configure_syscall_buffer_num(falco::
return run_result::fatal("cannot get the number of online CPUs from the system\n");
}
if(s.config->m_cpus_for_each_syscall_buffer > online_cpus)
if(s.config->m_modern_ebpf.m_cpus_for_each_buffer > online_cpus)
{
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;
falco_logger::log(falco_logger::level::WARNING, "you required a buffer every '" + std::to_string(s.config->m_modern_ebpf.m_cpus_for_each_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_modern_ebpf.m_cpus_for_each_buffer = online_cpus;
}
#endif
return run_result::ok();

View File

@@ -28,21 +28,15 @@ 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.
*/
if(s.is_capture_mode()
|| !s.is_source_enabled(falco_common::syscall_source)
|| s.is_gvisor_enabled()
|| s.options.nodriver)
auto index = s.driver_buf_size_preset();
if (index == -1)
{
// Chosen driver kind does not support this option.
return run_result::ok();
}
uint16_t index = s.config->m_syscall_buf_size_preset;
if(index < MIN_INDEX || index > MAX_INDEX)
{
return run_result::fatal("The 'syscall_buf_size_preset' value must be between '" + std::to_string(MIN_INDEX) + "' and '" + std::to_string(MAX_INDEX) + "'\n");
return run_result::fatal("The 'buf_size_preset' value must be between '" + std::to_string(MIN_INDEX) + "' and '" + std::to_string(MAX_INDEX) + "'\n");
}
/* Sizes from `1 MB` to `512 MB`. The index `0` is reserved, users cannot use it! */
@@ -55,24 +49,24 @@ falco::app::run_result falco::app::actions::configure_syscall_buffer_size(falco:
if(page_size <= 0)
{
s.syscall_buffer_bytes_size = DEFAULT_BYTE_SIZE;
falco_logger::log(LOG_WARNING, "Unable to get the system page size through 'getpagesize()'. Try to use the default syscall buffer dimension: " + std::to_string(DEFAULT_BYTE_SIZE) + " bytes\n");
falco_logger::log(falco_logger::level::WARNING, "Unable to get the system page size through 'getpagesize()'. Try to use the default syscall buffer dimension: " + std::to_string(DEFAULT_BYTE_SIZE) + " bytes\n");
return run_result::ok();
}
/* Check if the chosen size is a multiple of the page size. */
if(chosen_size % page_size != 0)
{
return run_result::fatal("The chosen syscall buffer size '" + std::to_string(chosen_size) + "' is not a multiple of your system page size '" + std::to_string(page_size) + "'. Please configure a greater 'syscall_buf_size_preset' value in the Falco configuration file\n");
return run_result::fatal("The chosen syscall buffer size '" + std::to_string(chosen_size) + "' is not a multiple of your system page size '" + std::to_string(page_size) + "'. Please configure a greater 'buf_size_preset' value in the Falco configuration file\n");
}
/* Check if the chosen size is greater than `2 * page_size`. */
if((chosen_size / page_size) <= 2)
{
return run_result::fatal("The chosen syscall buffer size '" + std::to_string(chosen_size) + "' is not greater than '2 * " + std::to_string(page_size) + "' where '" + std::to_string(page_size) + "' is your system page size. Please configure a greater 'syscall_buf_size_preset' value in the Falco configuration file\n");
return run_result::fatal("The chosen syscall buffer size '" + std::to_string(chosen_size) + "' is not greater than '2 * " + std::to_string(page_size) + "' where '" + std::to_string(page_size) + "' is your system page size. Please configure a greater 'buf_size_preset' value in the Falco configuration file\n");
}
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");
falco_logger::log(falco_logger::level::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();

Some files were not shown because too many files have changed in this diff Show More