Compare commits

...

393 Commits

Author SHA1 Message Date
Federico Di Pierro
0bf7458f3d chore(falco.yaml): rule -> rules.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-05-20 16:33:11 +02:00
Federico Di Pierro
d553662108 cleanup(falco.yaml): removed useless sentence.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-05-20 16:33:11 +02:00
Federico Di Pierro
a48965a00c chore(userspace,falco.yaml,unit_tests): configs_files -> config_files.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-05-20 16:33:11 +02:00
Federico Di Pierro
1b22c4566a chore(falco.yaml): added config maturity to index.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-05-20 16:33:11 +02:00
Federico Di Pierro
c03ce122e7 chore(docs): added falco.yaml section about config keys maturity.
Also, rename `Experimental` -> `Incubating` and move `prometheus_metrics_enabled` to `Incubating`.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-05-20 16:33:11 +02:00
Melissa Kilby
0668c54485 cleanup(metrics): use sha26_rules (plural form) as naming
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-05-20 10:25:10 +02:00
Melissa Kilby
27bab30017 cleanup(metrics): add original rule name as label
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-05-20 10:25:10 +02:00
Federico Di Pierro
dfbd1810f9 update(cmake): bumped libs to 0.17.0-rc1 and falcoctl to v0.8.0-rc6.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-05-17 17:11:58 +02:00
Melissa Kilby
b0f352e7b9 cleanup(test): add test cases for sanitize_metric_name
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-05-17 14:54:58 +02:00
Melissa Kilby
c15a309781 clenaup: add sanitize_metric_name helper
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-05-17 14:54:58 +02:00
Melissa Kilby
e9afe24e17 cleanup(metrics): simplify some logic
Co-authored-by: Samuel Gaist <samuel.gaist@idiap.ch>
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-05-17 14:54:58 +02:00
Melissa Kilby
aa021537d9 cleanup(metrics): improve comments
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-05-17 14:54:58 +02:00
Melissa Kilby
0195dba889 cleanup: add getter functions to stats_manager
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-05-17 14:54:58 +02:00
Melissa Kilby
b7adcd251d new(metrics): add rules_counters_enabled option
Intended to replace https://github.com/falcosecurity/falco-exporter
when used with Prometheus output

Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-05-17 14:54:58 +02:00
Jason Dellaluce
64039196ad chore(unit_tests): fix linting issue
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2024-05-17 14:38:57 +02:00
Jason Dellaluce
ec9f148e0b test(engine): cover case of replaced or appended exceptions
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2024-05-17 14:38:57 +02:00
Jason Dellaluce
e211e97e2a fix(userspace/engine): make sure exception fields are not optional in replace mode
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2024-05-17 14:38:57 +02:00
Federico Di Pierro
1bf6a83e31 new(docker): added zstd dep.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-05-17 13:38:57 +02:00
Luca Guerra
b5461e11a7 new(ci): sign .tar.gz packages
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-05-17 10:17:56 +02:00
Federico Di Pierro
c8072d2640 update(cmake): bumped falcoctl to v0.8.0-rc5.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-05-16 14:41:54 +02:00
Melissa Kilby
6057c1553e cleanup(engine): print total number of enabled rules
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-05-16 10:29:53 +02:00
Melissa Kilby
77341cbd2e new(engine): add print_enabled_rules_falco_logger when log_level debug
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-05-16 10:29:53 +02:00
dependabot[bot]
0869abc65e build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `4f153f5` to `29c41c4`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](4f153f53ae...29c41c4eed)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-16 09:37:53 +02:00
Luca Guerra
eb3ee5d2b2 update(falco): add deprecation warning messages
Signed-off-by: Luca Guerra <luca@guerra.sh>
Co-authored-by: Federico Di Pierro <nierro92@gmail.com>
Co-authored-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-05-15 10:33:50 +02:00
Luca Guerra
f9a56d9c9d update(falco): add deprecation notice for -T, -t and -D
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-05-15 10:33:50 +02:00
Luca Guerra
abf82f6373 update(config): split init_from_content from init_from_file
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-05-14 12:47:46 +02:00
Luca Guerra
f6ae8c8470 update(config): experimental->incubating
Co-authored-by: Leonardo Grasso <me@leonardograsso.com>
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-05-14 12:47:46 +02:00
Luca Guerra
02afb39a85 new(engine): add 'rules' section description to falco.yaml
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-05-14 12:47:46 +02:00
Luca Guerra
35bd348e21 new(falco): implement rule selection configuration in falco.yaml
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-05-14 12:47:46 +02:00
Melissa Kilby
60e6798f9b cleanup(metrics): use map for config and rules filenames sha256 tracking
Co-authored-by: Federico Di Pierro <nierro92@gmail.com>
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-05-14 10:08:51 +02:00
Melissa Kilby
91b58c43f1 chore: fix non linux build metrics
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-05-14 10:08:51 +02:00
Melissa Kilby
67a5015be7 cleanup(metrics): use filesystem lib to derive file names + build fix
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-05-14 10:08:51 +02:00
Melissa Kilby
34ecd39113 new(metrics): add file sha256sum metrics for loaded config and rules files
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-05-14 10:08:51 +02:00
Melissa Kilby
2b80cf85ac new(utils): add new helper to calculate file sha256sum
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-05-14 10:08:51 +02:00
Federico Di Pierro
44c275dee8 update(cmake): bumped falcoctl to v0.8.0-rc4.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-05-13 18:32:43 +02:00
Federico Di Pierro
cf88a8cdf8 update(cmake): bump falcoctl to v0.8.0-rc3
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-05-13 18:32:43 +02:00
Federico Di Pierro
dd9163c6f4 fix(userspace/falco): fix state inizialization.
This fixes an ugly segfault happening during hot reload.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-05-09 10:43:58 +02:00
Jason Dellaluce
d17f2afe4f update(cmake): bump libs and driver to a8fdacdb
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2024-05-08 20:23:55 +02:00
Jason Dellaluce
b2e4cddcdf fix(userspace/falco): inizialize options variables
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2024-05-08 20:23:55 +02:00
Jason Dellaluce
c6e3cfd115 test(engine): cover transformers and field-to-field checks in exceptions
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2024-05-08 20:23:55 +02:00
Jason Dellaluce
f18ea1e8b7 update(userspace/engine): support tranformers in exception fields
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2024-05-08 20:23:55 +02:00
Jason Dellaluce
fa8e780b07 update(userspace/engine): propagate compiler warnings
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2024-05-08 20:23:55 +02:00
Jason Dellaluce
bc078f1f63 update(userspace/engine): support comparins with right-hand fields
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2024-05-08 20:23:55 +02:00
Jason Dellaluce
ed22e94292 refactor(userspace/libsinsp): support new filter ast structure in falco engine
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2024-05-08 20:23:55 +02:00
Federico Aponte
62d1c4fc4d refactor: smart pointer usage
Signed-off-by: Federico Aponte <federico.aponte@sysdig.com>
2024-05-06 11:10:44 +02:00
dependabot[bot]
96c47e5eeb build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `ec255e6` to `4f153f5`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](ec255e68f4...4f153f53ae)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-06 10:33:44 +02:00
Federico Di Pierro
ec0f8077e1 update(cmake): bump libs and driver to latest master.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-05-03 12:12:02 +02:00
Andrea Terzolo
0999d45fbf bump ro rc4
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-05-03 12:12:02 +02:00
Federico Di Pierro
20c394ba34 chore(cmake): bumped libs to 0.16.0-rc2.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-05-03 12:12:02 +02:00
Andrea Terzolo
e2c2b50b3b chore: disable TLS sanitizer
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-05-03 12:12:02 +02:00
Andrea Terzolo
db1be96ad9 chore: tmp bump to libs master to test Falco CI
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-05-03 12:12:02 +02:00
Federico Di Pierro
6954a4028e chore(userspace/engine): bump version and checksum.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-05-03 12:12:02 +02:00
Federico Di Pierro
937637f668 update(cmake): bumped falcoctl to v0.8.0-rc2.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-05-03 12:12:02 +02:00
Federico Di Pierro
8b477bdc00 update(cmake): bumped libs and driver to latest RCs.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-05-03 12:12:02 +02:00
Samuel Gaist
cbfe77d1a0 fix(falco_metrics): remove falco_ prefix for version
The textual content was fixed but not the metrics name.

Co-authored-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-05-03 11:23:02 +02:00
Samuel Gaist
66d1970952 fix(falco_metrics): make duration_sec and outputs_queue_num_drops monotonic
Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-05-03 11:23:02 +02:00
Samuel Gaist
1316b0f448 chore(configuration): add reference to Prometheus endpoint in metrics documentation
The cross reference makes it easier to pair the web server and the
metrics configuration elements.

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-05-03 11:23:02 +02:00
Samuel Gaist
82c914c11d fix(falco_metrics): make duration_sec a count and not a timestamp
The output will thus be a total which is what this metrics is.

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-05-03 11:23:02 +02:00
Samuel Gaist
2ae6103ab6 fix(falco_metrics): remove redundant falco in version metrics
Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-05-03 11:23:02 +02:00
Samuel Gaist
65331c0f20 feat(falco_metrics): add event sources
Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-05-03 11:23:02 +02:00
Samuel Gaist
1ba35c911a feat(falco_metrics): add duration_sec
Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-05-03 11:23:02 +02:00
Samuel Gaist
5ef8f1c311 feat(falco_metrics): add outputs_queue_num_drops
Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-05-03 11:23:02 +02:00
Samuel Gaist
f90dbf9b77 refactor(metrics): use prometheus_metrics_enabled for configuration
As agreed upon during review, use this name to get started. If more
backends were to be added, the configuration structure will be updated.

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-05-03 11:23:02 +02:00
Samuel Gaist
5c237a07dc refactor(metrics): make to_text get the application state
As falco may update its state at any time and thus its inspectors objects,
keeping pointers to them may end up in using dangling values.

Therefore, use the state of the application when requesting metrics.

Optimizations such as caching of mostly static values will be done in
a follow up patch.

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-05-03 11:23:02 +02:00
Samuel Gaist
a0c109fcff refactor(falco_metrics): put content type in documented constant
This will keep things clearer and also allow for easir update in
the future.

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-05-03 11:23:02 +02:00
Samuel Gaist
9cc44c0eb7 doc(falco_metrics): add basic documentation
Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-05-03 11:23:02 +02:00
Samuel Gaist
de7a70ea54 fix(metrics): correct hostname metrics name and namespace
Co-authored-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-05-03 11:23:02 +02:00
Samuel Gaist
53722a26bf fix(metrics): correct static metrics
Things to fix:
- type
- name
- unit

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-05-03 11:23:02 +02:00
Samuel Gaist
59c290dc80 fix(metrics): correct metrics namespace
Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-05-03 11:23:02 +02:00
Samuel Gaist
daf7efde67 refactor(metrics): move metrics handling to its own class
This will keep the details out of the webserver itself and make
it easier to manage metrics.

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-05-03 11:23:02 +02:00
Samuel Gaist
e50d647dc9 refactor(configuration): move webserver items in own struct
This makes things easier to pass around like when starting the
web server.

This has the added benefit of simplifying further extension such as
making the metrics endpoint name configurable without adding yet another
parameter to the start function.

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-05-03 11:23:02 +02:00
Samuel Gaist
968a403cba refactor(webserver): move metrics endpoint activation under webserver
Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-05-03 11:23:02 +02:00
Samuel Gaist
cd073a033a fix(webserver): use falcosecurity as metric namespace
Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-05-03 11:23:02 +02:00
Samuel Gaist
4819877b9f fix(webserver): remove extra line return
The converter already provides properly formatted text.

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-05-03 11:23:02 +02:00
Samuel Gaist
3a251beea7 fix(webserver): correct enabled check
It was checking twice for prometheus configuration rather than metrics and then prometheus.

Co-authored-by: Federico Di Pierro <nierro92@gmail.com>
Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-05-03 11:23:02 +02:00
Samuel Gaist
8f1b2dc909 feat(webserver): implement metrics endpoint
This endpoint currently returns only prometheus metrics.

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-05-03 11:23:02 +02:00
Federico Di Pierro
61dab93eb3 chore(ci): fixed BUILD_FALCO_MODERN_BPF usages.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-24 16:49:26 +02:00
Federico Di Pierro
cc09811303 chore(cmake): enable modern bpf build by default.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-24 16:49:26 +02:00
Luca Guerra
d0945e5db5 cleanup(docs): fix typo in license blocks
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-04-19 16:52:58 +02:00
Federico Di Pierro
bdcfbba90b chore(docker,scripts): set old eBPF probe as lowest priority driver.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-18 11:18:54 +02:00
dependabot[bot]
b239246ff8 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `869c9a7` to `ec255e6`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](869c9a7f4d...ec255e68f4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-18 09:44:54 +02:00
Luca Guerra
814c510d7e update(app): close inspectors at teardown time
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-04-17 18:39:54 +02:00
Gianmatteo Palmieri
eb04b1c66f fix(test): expect warning instead of error on invalid macro/list name
Signed-off-by: Gianmatteo Palmieri <mail@gian.im>
2024-04-17 11:27:52 +02:00
Gianmatteo Palmieri
dd59c48034 new(engine): raise warning instead of error on invalid macro/list name
Signed-off-by: Gianmatteo Palmieri <mail@gian.im>
2024-04-17 11:27:52 +02:00
Federico Di Pierro
e21a3a5e58 chore(userspace/falco): make it clear singular vs plural.
Co-authored-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-16 16:39:47 +02:00
Federico Di Pierro
92c1b24905 chore(falco.yaml): small improvements.
Co-authored-by: Leonardo Grasso <me@leonardograsso.com>
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-16 16:39:47 +02:00
Federico Di Pierro
a2a8c6c3d4 chore(userspace/falco): deprecate old 'rules_file' config key.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-16 16:39:47 +02:00
Federico Di Pierro
80a99b672f fix(docker): default to auto for driver to be configured.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-16 14:44:46 +02:00
Federico Di Pierro
fc7a451aed fix(docker): fixed docker entrypoints for driver loading.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-16 14:44:46 +02:00
Federico Di Pierro
ac61543276 fix(docker,scripts): do not load falcoctl driver loader when installing Falco deb package in docker image.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-15 17:22:44 +02:00
Federico Di Pierro
7cc57a9fa0 docs(scripts): leave a small comment.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-15 15:13:44 +02:00
Federico Di Pierro
cb414f1254 chore(docker): support new automatic driver selection in docker images entrypoints.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-15 15:13:44 +02:00
Federico Di Pierro
bb939959a7 update(falco.yaml): set modern_ebpf as default engine kind.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-15 15:13:44 +02:00
Federico Di Pierro
2ede48ccfc chore(scripts): updated debian and rpm post installation scripts to deal with new automatic driver selection as default behavior.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-15 15:13:44 +02:00
Federico Di Pierro
53d13f8bfc chore(scripts): dynamically set falcoctl allowed driver types based on cmake configuration.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-15 15:13:44 +02:00
Federico Di Pierro
2eb519380a update(cmake,scripts): bumped falcoctl to v0.8.0-rc1.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-15 15:13:44 +02:00
Gianmatteo Palmieri
c3d0579d9b fix(test): expect warning instead of error in exceptions names test
Signed-off-by: Gianmatteo Palmieri <mail@gian.im>
2024-04-11 17:22:28 +02:00
Gianmatteo Palmieri
83910be726 new(engine): raise warning instead of error on not-unique exceptions names
Signed-off-by: Gianmatteo Palmieri <mail@gian.im>
2024-04-11 17:22:28 +02:00
Luca Guerra
7ac5c36d5a update(ci): build both release and debug versions
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-04-10 16:10:20 +02:00
Federico Di Pierro
8b340d3903 chore(userspace/falco): watch all configs files.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-10 15:57:20 +02:00
Federico Di Pierro
e840a4ada0 new(unit_tests,userspace/falco): support loading and merging configs files when used from cmdline option.
Also, moved core logic from yaml_helper to falco_configuration class.
Finally, updated tests.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-10 14:44:20 +02:00
Federico Di Pierro
faabd41d9e chore(falco.yaml): add configs_files to falco yaml index.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-10 14:44:20 +02:00
Federico Di Pierro
a8345327d4 chore(unit_tests,userspace/falco): throw an exception when included config file is not present.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-10 14:44:20 +02:00
Federico Di Pierro
de9efcbec7 new(userspace/falco): allow --support to print expanded configuration file.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-10 14:44:20 +02:00
Federico Di Pierro
2a856f2cd3 chore(unit_tests): assert expected length of warnings.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-10 14:44:20 +02:00
Federico Di Pierro
74034213a2 chore(unit_test,userspace): better log management.
Also, warnings are now returned so that yaml_helper class does not need to log anything.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-10 14:44:20 +02:00
Federico Di Pierro
aac9b550d3 new(userspace,unit_tests): return loaded config filenames in config::load_from_file.
Add a debug log with the list of loaded config files.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-10 14:44:20 +02:00
Federico Di Pierro
df220e3c3b chore(userspace,unit_tests): support loading config files from directories.
The files inside the folder will be loaded in lexicographic order,
like we do for rules_file.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-10 14:44:20 +02:00
Federico Di Pierro
5e51828509 chore(build): install a config.d folder under the falco directory.
Also, include it in the config file.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-10 14:44:20 +02:00
Federico Di Pierro
d3bf3a7560 chore(userspace/falco,unit_tests): renamed includes to configs_files.
Moreover, split single huge test into multiple smaller ones.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-10 14:44:20 +02:00
Federico Di Pierro
1deafee5f7 chore(userspace/falco): print a warn message if -o includes= is passed to cmdline.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-10 14:44:20 +02:00
Federico Di Pierro
45754fda9f new(userspace,unit_tests): deny main config to include itself.
Moreover, added a couple more tests.

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

Co-authored-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-04-10 14:44:20 +02:00
Federico Di Pierro
8112f6210b chore(userspace,unit_tests): enable override of main config from secondary config files.
Moreover, do not trigger an exception when an included file is not present; just print a warning.
Finally, add more tests.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-10 14:44:20 +02:00
Federico Di Pierro
6e1f128851 chore(unit_tests): more tests.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-10 14:44:20 +02:00
Federico Di Pierro
b3ebf9f57e new(userspace,unit_tests): introduce the possibility to split main config file into multiple config files.
The PR introduces a `includes` keyword in the config file,
that points to a list of strings (paths to other config files).

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-04-10 14:44:20 +02:00
Luca Guerra
3cbc4aa29c chore(falco): update falco libs to latest master
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-04-08 17:18:13 +02:00
dependabot[bot]
39cb0a8a67 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `88a40c8` to `869c9a7`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](88a40c8d9c...869c9a7f4d)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-05 19:02:03 +02:00
Gianmatteo Palmieri
7234bc5bee chore(engine): bump engine version
Signed-off-by: Gianmatteo Palmieri <mail@gian.im>
2024-04-03 18:23:53 +02:00
Gianmatteo Palmieri
368463e295 new(tests): add unique exceptions names test
Signed-off-by: Gianmatteo Palmieri <mail@gian.im>
2024-04-03 18:23:53 +02:00
Gianmatteo Palmieri
05c434ed89 new(engine): enforce unique exceptions names
Signed-off-by: Gianmatteo Palmieri <mail@gian.im>
2024-04-03 18:23:53 +02:00
Luca Guerra
05e6e3038c chore(build): update scorecard-action to v2.3.1
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-04-02 16:53:45 +02:00
Luca Guerra
b01ef55f6b new(ci): build with sanitizers in CI
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-03-29 14:08:24 +01:00
Luca Guerra
f895f8fc78 fix(tests): fix uninitialized variable in test
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-03-29 14:08:24 +01:00
Luca Guerra
b82c73c66c new(build): add option to build with ASAN and UBSAN
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-03-29 14:08:24 +01:00
Luca Guerra
1aae10fe84 update(engine): bump engine checksum and version
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-03-29 10:16:23 +01:00
Luca Guerra
0d40a718c8 update(build): bump libs to latest master
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-03-29 10:16:23 +01:00
Luca Guerra
13c8e37a41 cleanup(falco): consolidate falco::grpc::server in one class
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-03-28 10:16:15 +01:00
Gianmatteo Palmieri
a8018a2894 new(tests): test override/append exception with no values
Signed-off-by: Gianmatteo Palmieri <mail@gian.im>
2024-03-27 09:15:13 +01:00
Gianmatteo Palmieri
7086f35eba new(engine): add warning when appending an exception with no values
Signed-off-by: Gianmatteo Palmieri <mail@gian.im>
2024-03-27 09:15:13 +01:00
Gianmatteo Palmieri
d1707bef63 fix(engine): apply output substitutions for all sources
Signed-off-by: Gianmatteo Palmieri <mail@gian.im>
2024-03-25 19:33:06 +01:00
dependabot[bot]
1882def2a6 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `fbf0a4e` to `88a40c8`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](fbf0a4e8ce...88a40c8d9c)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-25 19:06:06 +01:00
Luca Guerra
8421e4b122 fix(cmake): fix USE_BUNDLED_DEPS=ON and BUILD_FALCO_UNIT_TESTS=ON
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-03-25 16:47:06 +01:00
Paul Rey
12cd72a396 Remove --source-only option in driver loader docker-entrypoint.sh
The option is supported anymore in falcoctl

Signed-off-by: Paul Rey <contact@paulrey.io>
2024-03-22 13:45:53 +01:00
Paul Rey
858c82ffe0 Update driver-loader docker-entrypoint
Remove debug log
Set default option ENABLE_COMPILE and ENABLE_DOWNLOAD

Signed-off-by: Paul Rey <contact@paulrey.io>
2024-03-22 13:45:53 +01:00
Paul Rey
2f6fdfa972 Add kernelversion and kernelrelease options to falco driver loader entrypoint
Signed-off-by: Paul Rey <contact@paulrey.io>
2024-03-22 13:45:53 +01:00
dependabot[bot]
2dfac14cd1 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `44addef` to `fbf0a4e`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](44addef4f7...fbf0a4e8ce)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-15 09:41:27 +01:00
Federico Di Pierro
5fe9fc9d89 update(cmake): bumped libs and driver to 0.15.0-rc1.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-03-14 10:55:24 +01:00
Melissa Kilby
3b7b3439ec cleanup(metrics): fix build for non linux
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-03-14 10:55:24 +01:00
Melissa Kilby
7762d0cd84 chore: bump libs
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-03-14 10:55:24 +01:00
Melissa Kilby
09d813b22d feat(metrics): sync libs metrics collector refactor
Includes a handful of naming changes. A notice to
https://falco.org/docs/metrics/falco-metrics/ will be added well
in advance of Falco 0.38.0

falco.hostname -> evt.hostname to be consistent with the newer evt.hostname filtercheck
cpu_usage_perc_total_host -> host_cpu_usage_perc
memory_used_host -> host_memory_used_kb (or host_memory_used_mb)
procs_running_host -> host_procs_running
open_fds_host -> host_open_fds

memory_rss -> memory_rss_kb (or memory_rss_mb)
memory_pss -> memory_pss_kb (or memory_pss_mb)
memory_vsz -> memory_vsz_kb (or memory_vsz_mb)
container_memory_used -> container_memory_used_bytes (or container_memory_used_mb)

Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-03-14 10:55:24 +01:00
Andrea Terzolo
3395e604b6 ci: use ubuntu-22.04 with codeQL job
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-03-12 16:29:17 +01:00
Andrea Terzolo
0ce2b95b89 chore: bump falco engine version
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-03-12 16:29:17 +01:00
Andrea Terzolo
c5bb2b68e2 chore: bump to latest libs commit
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-03-12 16:29:17 +01:00
Federico Aponte
8dbec6c779 refactor: Use FetchContent for integrating bundled yaml-cpp lib
Signed-off-by: Federico Aponte <federico.aponte@sysdig.com>
2024-03-11 13:57:15 +01:00
Federico Aponte
c32b7c1246 refactor: Use FetchContent for integrating bundled cpp-httplib
Signed-off-by: Federico Aponte <federico.aponte@sysdig.com>
2024-03-11 13:57:15 +01:00
Federico Aponte
bc499e191d refactor: Use FetchContent for integrating bundled nlohman-json lib
Signed-off-by: Federico Aponte <federico.aponte@sysdig.com>
2024-03-11 13:57:15 +01:00
dependabot[bot]
ea187d3b45 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `dc7970d` to `44addef`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](dc7970d175...44addef4f7)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-11 09:38:14 +01:00
Gianmatteo Palmieri
517b79ee13 chore(engine): bump engine version
Signed-off-by: Gianmatteo Palmieri <mail@gian.im>
2024-03-08 00:02:01 +01:00
Gianmatteo Palmieri
3d4be156cc new(tests): add unit test for invalid macro/list name
Signed-off-by: Gianmatteo Palmieri <mail@gian.im>
2024-03-08 00:02:01 +01:00
Gianmatteo Palmieri
7265190e66 new(engine): don't expose details in error message
Signed-off-by: Gianmatteo Palmieri <mail@gian.im>
2024-03-08 00:02:01 +01:00
Gianmatteo Palmieri
f00926b8af new(engine): error on invalid macro/list name
Signed-off-by: Gianmatteo Palmieri <mail@gian.im>
2024-03-08 00:02:01 +01:00
dependabot[bot]
a473ae5eb8 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `f88b991` to `dc7970d`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](f88b991a7f...dc7970d175)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-07 11:39:58 +01:00
Federico Aponte
3954ff233b refactor(ci): Avoid using command make directly
Signed-off-by: Federico Aponte <federico.aponte@sysdig.com>
2024-03-07 11:37:58 +01:00
Leonardo Grasso
a5297c4f29 docs(proposals/20231220-features-adoption-and-deprecation): general revision
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2024-03-06 14:34:55 +01:00
Leonardo Grasso
eb35ea7dfe docs(proposals/20231220-features-adoption-and-deprecation): add Platform support area
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2024-03-06 14:34:55 +01:00
Leonardo Grasso
63ccf872fd Update proposals/20231220-features-adoption-and-deprecation.md
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2024-03-06 14:34:55 +01:00
Leonardo Grasso
3bdb98a46b Update proposals/20231220-features-adoption-and-deprecation.md
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2024-03-06 14:34:55 +01:00
Leonardo Grasso
c68ef54bb2 docs(proposals/20231220-features-adoption-and-deprecation): remove feature gates, simplify policies and transition phases
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2024-03-06 14:34:55 +01:00
Leonardo Grasso
865553dbe3 docs(proposals/20231220-features-adoption-and-deprecation): only stable features deprecation require a major bump
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2024-03-06 14:34:55 +01:00
Leonardo Grasso
10a9c1d774 docs(proposal): 20231220-features-adoption-and-deprecation.md
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2024-03-06 14:34:55 +01:00
Aldo Lacuku
185075bfd8 update(scrips/falcoctl): bump falco-rules version to 3
Signed-off-by: Aldo Lacuku <aldo@lacuku.eu>
2024-03-06 07:35:54 +01:00
Melissa Kilby
5185f152c5 new(config): add falco_libs.thread_table_size
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-03-05 11:36:51 +01:00
Samuel Gaist
8f87b117c4 fix(userspace): correct directory iteration options
The original code was using follow_directory_symlink twice, this patch
fixes that.

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-03-05 10:29:51 +01:00
dependabot[bot]
5084a62dd1 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `b499a1d` to `f88b991`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](b499a1d0d0...f88b991a7f)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-01 12:05:36 +01:00
Leonardo Grasso
ca4db17e05 docs(README.md): Falco Graduates within the CNCF
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2024-02-29 16:41:33 +01:00
Samuel Gaist
f9b17b67f8 refactor(engine): fix variable / function shadowing
Improve variable names in the code surrounding the changes.

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-02-29 16:20:34 +01:00
Samuel Gaist
8a7361c8ab refactor(app): fix variable / function shadowing
Improve variable names in the code surrounding the changes.

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-02-29 16:20:34 +01:00
dependabot[bot]
2589bd0c0b build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `497e011` to `b499a1d`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](497e01189e...b499a1d0d0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-28 11:16:27 +01:00
Gianmatteo Palmieri
928cb8bb8e new(tests): add unit test for exceptions condition
Signed-off-by: Gianmatteo Palmieri <mail@gian.im>
2024-02-28 08:28:26 +01:00
Gianmatteo Palmieri
ea781477d6 fix(engine): logical issue in exceptions condition
Signed-off-by: Gianmatteo Palmieri <mail@gian.im>
2024-02-28 08:28:26 +01:00
Federico Di Pierro
f6818902de fix(ci): properly enforce bundled deps off in build-dev, like it was before https://github.com/falcosecurity/falco/pull/3092.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-02-27 11:07:25 +01:00
Federico Di Pierro
5ebc7bbd7c chore(ci): bumped codeql actions.
Moveover, to avoid spending too much time (and space) on the job, build without bundled deps.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-02-26 17:55:21 +01:00
Federico Aponte
f6af72fe76 cleanup: too many includes and useless defines
Signed-off-by: Federico Aponte <federico.aponte@sysdig.com>
2024-02-26 14:59:22 +01:00
Federico Aponte
4d66a50d5b fix: pessimizing move warning
Signed-off-by: Federico Aponte <federico.aponte@sysdig.com>
2024-02-26 14:59:22 +01:00
Federico Aponte
59c14f46a2 refactor: shared_ptr construction
Signed-off-by: Federico Aponte <federico.aponte@sysdig.com>
2024-02-26 14:59:22 +01:00
Federico Aponte
557929a82a refactor: use object rather than unique_ptr
Signed-off-by: Federico Aponte <federico.aponte@sysdig.com>
2024-02-26 14:59:22 +01:00
Federico Aponte
9a2b58c6f7 refactor: very minor improvement
Signed-off-by: Federico Aponte <federico.aponte@sysdig.com>
2024-02-26 14:59:22 +01:00
Gianmatteo Palmieri
1705fc2281 refactor(build): use find_package when possible
Signed-off-by: Gianmatteo Palmieri <mail@gian.im>
2024-02-23 15:43:08 +01:00
Gianmatteo Palmieri
97806a98fb new(build): add options to use bundled yamlcpp and njson
Signed-off-by: Gianmatteo Palmieri <mail@gian.im>
2024-02-23 15:43:08 +01:00
Gianmatteo Palmieri
736277d3d5 new(build): switch USE_BUNDLED_DEPS default value to ON
Signed-off-by: Gianmatteo Palmieri <mail@gian.im>
2024-02-23 15:43:08 +01:00
Gianmatteo Palmieri
bc804c44a0 refactor(build): set bundled deps default value
Signed-off-by: Gianmatteo Palmieri <mail@gian.im>
2024-02-23 15:43:08 +01:00
Gianmatteo Palmieri
91e74b1b19 cleanup(build): remove bundled dep check
Signed-off-by: Gianmatteo Palmieri <mail@gian.im>
2024-02-23 15:43:08 +01:00
Gianmatteo Palmieri
0fd3732422 new(build): add options to use system libcxxopts and libcpp-httplib
Signed-off-by: Gianmatteo Palmieri <mail@gian.im>
2024-02-23 15:43:08 +01:00
Federico Di Pierro
60ef759c70 fix(ci): test-dev-packages-arm64 needs build-dev-packages-arm64.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-02-23 15:42:08 +01:00
Jason Dellaluce
02ad182b48 fix(cmake): solve windows compilation issues
Co-authored-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2024-02-23 11:39:07 +01:00
Jason Dellaluce
3b06fb2cbb fix(userspace): solve compilation issues
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2024-02-23 11:39:07 +01:00
Jason Dellaluce
c13cf79aab update(engine): bump engine version
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2024-02-23 11:39:07 +01:00
Jason Dellaluce
9b4c1a0023 update(cmake): bump libs and driver to latest
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2024-02-23 11:39:07 +01:00
Jason Dellaluce
0ec2a6c708 refactor(userspace): reduce usage of raw pointers
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2024-02-23 11:39:07 +01:00
Jason Dellaluce
b515f0a079 refactor(usersapace): adapt to changes libs
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2024-02-23 11:39:07 +01:00
Melissa Kilby
4ed11d90a4 chore: rename plugin name to more expressive anomalydetection term
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-02-22 10:20:05 +01:00
Melissa Kilby
bf55a7e86e update(proposals): minor enhancements and falco community call feedback
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-02-22 10:20:05 +01:00
Melissa Kilby
2f2bd6e93e update(proposals): minor enhancements and kubeconna23 feedback
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-02-22 10:20:05 +01:00
Melissa Kilby
534afca5f5 new(proposals): introduce on host anomaly detection framework
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-02-22 10:20:05 +01:00
Federico Di Pierro
71a0d0d186 fix(cmake): properly let falcoctl cmake module create /usr/share/falco/plugins/ folder.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-02-21 10:05:02 +01:00
Federico Aponte
b4e55ee6a1 cleanup: falco_engine test fixture
Upgrade GTest to 1.14.0

Signed-off-by: Federico Aponte <federico.aponte@sysdig.com>
2024-02-21 00:31:59 +01:00
Federico Aponte
745d18ba38 refactor: test AtomicSignalHandler.handle_once_wait_consistency
Signed-off-by: Federico Aponte <federico.aponte@sysdig.com>
2024-02-20 15:19:56 +01:00
Samuel Gaist
05e796723f fix(userspace): remove unread variable in restart_handler
When hitting that part, the restart signal is triggered and the code
leaves the loop, hence setting should_restart as false makes no sense
in this context.

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-02-19 18:01:48 +01:00
Samuel Gaist
ad585cd46b fix(actions): remove unused variable in print_support
Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-02-19 18:01:48 +01:00
Samuel Gaist
e07f056fc5 fix(tests): remove unused variables in rule loader tests
Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-02-19 18:01:48 +01:00
Federico Di Pierro
1178a0505c cleanup(submodules): dropped testing submodule.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-02-19 17:06:48 +01:00
Federico Di Pierro
fbe45125ae cleanup(ci): make use of falcosecurity/testing provided composite action.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-02-19 10:56:47 +01:00
Andrea Terzolo
a44bee57d9 fix(CI): fix windows CI
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-02-16 18:30:38 +01:00
Andrea Terzolo
d49b21ab22 cleanup: move ebpf default value logic
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-02-16 18:30:38 +01:00
Andrea Terzolo
76ab28ff59 tests: remove deprecated assertions
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-02-16 18:30:38 +01:00
Andrea Terzolo
99781f7936 cleanup(configuration): cleanup deprecated code
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-02-16 18:30:38 +01:00
Andrea Terzolo
9c182d23f6 cleanup(falco.yaml)!: remove deprecated configs
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-02-16 18:30:38 +01:00
Samuel Gaist
5e497a4119 fix(c++): improve const correctness
Reported by cppcheck

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-02-15 22:16:33 +01:00
dependabot[bot]
792bcdca18 build(deps): Bump submodules/falcosecurity-testing
Bumps [submodules/falcosecurity-testing](https://github.com/falcosecurity/testing) from `ae3950a` to `7abf76f`.
- [Commits](ae3950acf0...7abf76f2a0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-15 19:41:33 +01:00
Luca Guerra
5564d3da11 cleanup(app): ensure unbuffered_outputs is initialized
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-02-15 11:03:30 +01:00
Luca Guerra
fe5c58e20e cleanup(tests): use test_falco_engine in test_enable_rule
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-02-15 11:03:30 +01:00
Luca Guerra
baf9e77810 cleanup(tests): update configure_interesting_sets to use test_falco_engine
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-02-15 11:03:30 +01:00
Luca Guerra
1afacb45fb cleanup(tests): extract engine fixture
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-02-15 11:03:30 +01:00
Luca Guerra
12f57514ad cleanup(tests): pass a valid inspector to factory/ast/filter tests
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-02-15 11:03:30 +01:00
Samuel Gaist
e18acc361e fix(c++): don't throw outside of the try catch block in nothrow function
Reported by cppcheck

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-02-15 10:19:30 +01:00
Samuel Gaist
f3491d62c9 fix(c++): re-throw original exception rather than copy
Reported by cppcheck

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-02-15 10:19:30 +01:00
Federico Aponte
7a18795ca5 cleanup: falco_engine deps and include paths
Signed-off-by: Federico Aponte <federico.aponte@sysdig.com>
2024-02-15 10:08:30 +01:00
Federico Aponte
539dac0590 fix: Some compiler warnings
Signed-off-by: Federico Aponte <federico.aponte@sysdig.com>
2024-02-15 10:07:30 +01:00
dependabot[bot]
14650f49b6 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `0f60976` to `497e011`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](0f609769ef...497e01189e)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-14 19:38:27 +01:00
Andrea Terzolo
26add16d12 cleanup(docker)!: remove unused builder dockerfile
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-02-14 17:10:26 +01:00
Federico Di Pierro
3476555ad1 update(docs): added CHANGELOG entry for 0.37.1
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-02-13 10:37:21 +01:00
Melissa Kilby
3c2bd8d4d8 cleanup: minor adjustments to readme, add new testing section
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2024-02-13 10:21:22 +01:00
dependabot[bot]
f268f45923 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `6ed2036` to `0f60976`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](6ed2036d83...0f609769ef)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-12 18:46:18 +01:00
Samuel Gaist
8c98ca5e8d fix(c++): add missing member initialisation to grpc server
Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-02-12 18:45:18 +01:00
Samuel Gaist
d6b0810657 fix(c++): move trivial initializations to declaration site
Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-02-12 18:45:18 +01:00
Samuel Gaist
42f90817ad refactor: make falco_exception a std::runtime_error
The implementation provides more or less the same implementation
and thus it makes more sense to base it on std::runtime_error.

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-02-12 18:45:18 +01:00
Samuel Gaist
f6498cd8bd fix(c++): refactor member initialization in constructor initialization list
Reported by cppcheck

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>

# Conflicts:
#	userspace/engine/falco_common.h
2024-02-12 18:45:18 +01:00
Tom Müller
8bc32d248e Added http headers option for driver download in docker images
Signed-off-by: Tom Müller <60851960+toamto94@users.noreply.github.com>
2024-02-12 18:03:17 +01:00
Samuel Gaist
08f62200b1 fix(c++): add missing explicit to single argument constructors
Reported by cppcheck

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-02-12 16:59:17 +01:00
dependabot[bot]
48a7f3bcb4 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `1053b2d` to `6ed2036`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](1053b2d1b6...6ed2036d83)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-12 14:55:16 +01:00
Federico Di Pierro
6c29fdb1e5 update(cmake): bumped falcoctl to v0.7.2.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-02-12 11:13:16 +01:00
Jason Dellaluce
0cc1c5b44f refactor(userspace/engine): reduce allocations during rules loading
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2024-02-09 14:50:05 +01:00
Luca Guerra
d69f329b54 fix(ci): update sync in deb and rpm scripts with acl
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-02-09 10:33:04 +01:00
Samuel Gaist
a9e1bfef42 fix(c++): add missing overrides
Reported by cppcheck

Signed-off-by: Samuel Gaist <samuel.gaist@idiap.ch>
2024-02-09 08:24:03 +01:00
Federico Di Pierro
7879920570 chore(userspace/engine): introduce proper check to avoid future issues throwing an exception.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-02-08 15:13:59 +01:00
Federico Di Pierro
7bcbc08b52 fix(userspace/engine): always consider all rules (even the ones below min_prio) in m_rule_stats_manager.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>

Co-authored-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-02-08 15:13:59 +01:00
Tom Müller
71f3c77a1a fixed typo in print usage
fixed typo in the print usage description of the docker run command

Signed-off-by: Tom Müller <60851960+toamto94@users.noreply.github.com>
2024-02-08 10:16:59 +01:00
Tom Müller
56a4e31d18 added option for insecure http driver download
added option for insecure http driver download to the falco docker entrypoint.

Signed-off-by: Tom Müller <60851960+toamto94@users.noreply.github.com>
2024-02-08 10:16:59 +01:00
Tom Müller
159e3f6ffc added insecure http driver download
added insecure http driver download to the driver-loader-legacy entrypoint.

Signed-off-by: Tom Müller <60851960+toamto94@users.noreply.github.com>
2024-02-08 10:16:59 +01:00
Tom Müller
f62c38e9e8 added option for insecure http download
Added option for insecure http driver download in the docker-entrypoint.sh script. By passing --http-insecure to the container via an argument, the flag is forwarded to the falcoctl driver install command.

Signed-off-by: Tom Müller <60851960+toamto94@users.noreply.github.com>
2024-02-08 10:16:59 +01:00
Luca Guerra
b091522398 new(build): prune deb-dev and rpm-dev directories
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-02-07 16:46:57 +01:00
RohithRaju
195116fa09 update(scripts): address review requests
Signed-off-by: RohithRaju <rohithraju488@gmail.com>
2024-02-07 14:31:57 +01:00
RohithRaju
1b9c2da601 update(CI): publish wasm package as dev-wasm
Signed-off-by: RohithRaju <rohithraju488@gmail.com>
2024-02-07 14:31:57 +01:00
Jason Dellaluce
039069d0e1 update(engine): bump engine version and checksum
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2024-02-06 10:25:53 +01:00
Jason Dellaluce
58f8f14a1b fix(tests): solve last few compilation issues
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2024-02-06 10:25:53 +01:00
Jason Dellaluce
aca08ff744 update(cmake): bump libs and driver to 8df8817
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2024-02-06 10:25:53 +01:00
Jason Dellaluce
4cffcedba1 refactor: remove refs to gen_event class family
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2024-02-06 10:25:53 +01:00
Luca Guerra
0613f11980 fix(build): install libstdc++ in the Wolfi image
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-02-05 14:55:49 +01:00
Luca Guerra
ea67e47023 update(build): install libelf in the nodriver image
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-02-02 19:57:40 +01:00
Luca Guerra
7d0001269c update(build): include libelf in the distroless image
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-02-02 19:57:40 +01:00
Luca Guerra
30df5738a5 update(build): disable musl builds
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-02-02 19:57:40 +01:00
Luca Guerra
e3a3271c7a update(ci): add libelf to build containers
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-02-02 19:57:40 +01:00
Luca Guerra
b414b01aab update(ci): allow version/static checks to work even if libelf is not installed
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-02-02 19:57:40 +01:00
Luca Guerra
7d9cfd02e3 chore(falco): update engine checksum
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-02-02 19:57:40 +01:00
Luca Guerra
8309d88595 new(build): build with dynamic libelf by default
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-02-02 19:57:40 +01:00
Luca Guerra
871597f1fa chore(build): update libs and drivers to 9cd289c
Signed-off-by: Luca Guerra <luca@guerra.sh>
2024-02-02 19:57:40 +01:00
dependabot[bot]
8acbbde600 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `3cac61c` to `1053b2d`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](3cac61cfa9...1053b2d1b6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-01 10:28:37 +01:00
Roberto Scolaro
40f4ce008a chore(engine): bump engine version
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2024-01-31 11:53:35 +01:00
Roberto Scolaro
3d06b77de5 chore(engine): update falco engine checksum
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2024-01-31 11:53:35 +01:00
Roberto Scolaro
fa6d380940 update: bump libs+driver to bfbc007
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2024-01-31 11:53:35 +01:00
Roberto Scolaro
9557b74501 fix: adopt new libsinsp logger
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2024-01-31 11:53:35 +01:00
Roberto Scolaro
ce87f2a014 refactor(userspace): remove libs relative imports
Signed-off-by: Roberto Scolaro <roberto.scolaro21@gmail.com>
2024-01-31 11:51:37 +01:00
Federico Di Pierro
41ee64e006 chore(ci): bumped rn2md to latest master.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-01-31 11:39:35 +01:00
dependabot[bot]
eccb5a6baa build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `3f668d0` to `3cac61c`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](3f668d0568...3cac61cfa9)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-31 09:52:34 +01:00
Mark Stemm
e1fb55e046 Add unit test for alternate rules loader
Add a unit test for providing an alternate rules loader that also
demonstrates how users can define sub-classes that may want to extend
the falco rules syntax.

This test creates a test rules reader/collector/compiler that supports
top-level objects "test_object". The reader reads them and saves them
in the collector. The compiler iterates over all test_objects and puts
the property values into a single set<string>.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2024-01-30 20:24:33 +01:00
Mark Stemm
1e0430dff9 Make compile_condition() a protected method for use in subclasses
Move the part of compile_rule_infos that actually compiled a condition
string into a sinsp_filter into a standalone method
compile_condition(). That way it can be used by classes that derive
from rule_loader::compiler() and want to compile condition strings.

This implementation also saves the compiled filter as a part of the
falco_rule object so it does not need to be compiled again wihin the
falco engine after rules loading.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2024-01-30 20:24:33 +01:00
Mark Stemm
88a57bfd1a Add ability for rulesets to access falco engine state
Some rulesets may need information which is held by the falco_engine
that created this ruleset. So define a set of functions in a struct
and have setters/getters for those functions in the base class.

Derived classes can use the struct's functions to obtain the falco
engine information.

The only function so far is to obtain the filter_ruleset for a given
event source.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2024-01-30 20:24:33 +01:00
Mark Stemm
ce5a50cbb5 Add addl support for rules reader/compiler subclasses
To support subclasses that may extend the falco rules format, add
additional error/warning/item types for an extension item.

When subclasses report errors and warnings, they can use these
codes/item types in context objects and still provide an exact
line/column context.

Also make some previously static functions in rules reader protected
methods so they can be used in sub-classes.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2024-01-30 20:24:33 +01:00
Mark Stemm
eed5b906a8 Provide the entire compile output to ruleset vs individual add()s
In order to support external rules loaders that may extend the falco
rules format with new top level objects, move away from providing
individual filter objects to the filter_ruleset via calls to add().

Instead, pass the entire compile output returned by the compiler to
the ruleset using a new method add_compile_output(). Custom users can
then cast back the compile output to the appropriate derived class for
use in the ruleset.

Move the declaration of the compile output to a standalone class so it
can be used by rulesets without including the entire rules loader
header files, and add a new factory method new_compile_output() to the
compiler so it can create a derived class if necessary.

This change is
backwards-compatible with existing rulesets, as the default
implementation of add_compile_output() simply iterates over rules and
calls add() for each rule.

This change also speeds up rule loading. Previously, each rule
condition was compiled twice:

1. First, in the compiler, to see if it was valid.
2. Second, in the falco engine before providing each rule to the
ruleset.

Add the compiled filter to the falco_rule object instead of throwing
it away in the compiler.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2024-01-30 20:24:33 +01:00
Mark Stemm
2d0159ae05 Add ability to provide external rules reader/collector/compiler
In some cases, a user of the falco engine may want to extend the falco
rules format to provide additional objects to the rules file.

To support that, add a new method set_rule_loader() that allows a user
to provide classes that derive from
rule_loader::{reader,collector,compiler} and read those additional
objects from the rules file.

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2024-01-30 20:24:33 +01:00
Federico Di Pierro
f66780eb81 fix(ci): fixed release body driver version.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2024-01-30 13:26:32 +01:00
dependabot[bot]
67a7685c29 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `c39d31a` to `3f668d0`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](c39d31a0bc...3f668d0568)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-30 12:59:32 +01:00
Andrea Terzolo
135ce35ac2 new(docs): add changelog for 0.37.0
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
2024-01-30 11:57:31 +01:00
Leonardo Grasso
2e19960522 update(cmake/modules): bump Falco rules to 3.0
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2024-01-25 17:03:15 +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
183 changed files with 8048 additions and 4043 deletions

View File

@@ -16,22 +16,54 @@ jobs:
fetch-version:
uses: ./.github/workflows/reusable_fetch_version.yaml
build-dev-packages:
build-dev-packages-sanitizers-x86_64:
needs: [fetch-version]
uses: ./.github/workflows/reusable_build_packages.yaml
with:
arch: x86_64
version: ${{ needs.fetch-version.outputs.version }}
build_type: Debug
sanitizers: true
build-dev-packages-x86_64:
needs: [fetch-version]
uses: ./.github/workflows/reusable_build_packages.yaml
with:
arch: x86_64
version: ${{ needs.fetch-version.outputs.version }}
build_type: Release
build-dev-packages-arm64:
needs: [fetch-version]
uses: ./.github/workflows/reusable_build_packages.yaml
with:
arch: aarch64
version: ${{ needs.fetch-version.outputs.version }}
build_type: Debug
sanitizers: false
test-dev-packages:
needs: [fetch-version, build-dev-packages]
needs: [fetch-version, build-dev-packages-sanitizers-x86_64]
uses: ./.github/workflows/reusable_test_packages.yaml
# The musl build job is currently disabled because we link libelf dynamically and it is
# not possible to dynamically link with musl
# strategy:
# fail-fast: false
# matrix:
# static: ["static", ""]
with:
arch: x86_64
sanitizers: true
# static: ${{ matrix.static != '' && true || false }}
version: ${{ needs.fetch-version.outputs.version }}
test-dev-packages-arm64:
needs: [fetch-version, build-dev-packages-arm64]
uses: ./.github/workflows/reusable_test_packages.yaml
strategy:
fail-fast: false
matrix:
static: ["static", ""]
with:
arch: x86_64
arch: aarch64
static: ${{ matrix.static != '' && true || false }}
version: ${{ needs.fetch-version.outputs.version }}
@@ -42,7 +74,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:
@@ -55,6 +95,7 @@ jobs:
arch: x86_64
git_ref: ${{ github.event.pull_request.head.sha }}
minimal: false
sanitizers: true
build_type: Debug
cmd: "echo $(build/userspace/falco/falco -c ./falco.yaml --version | grep 'Engine:' | awk '{print $2}') $(echo $(build/userspace/falco/falco -c ./falco.yaml --version | grep 'Schema version:' | awk '{print $3}') $(build/userspace/falco/falco -c ./falco.yaml --list --markdown | grep '^`' | sort) $(build/userspace/falco/falco -c ./falco.yaml --list-events | sort) | sha256sum)"

View File

@@ -21,7 +21,7 @@ on:
jobs:
analyze:
name: Analyze
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
permissions:
actions: read
contents: read
@@ -42,13 +42,13 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9
uses: github/codeql-action/init@47b3d888fe66b639e431abf22ebca059152f1eea # v3.24.5
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,20 +56,15 @@ 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: |
mkdir build
pushd build
cmake -DBUILD_BPF=On ..
popd
cmake -B build -S . -DBUILD_BPF=On -DBUILD_FALCO_MODERN_BPF=Off -DUSE_BUNDLED_DEPS=Off -DUSE_BUNDLED_NLOHMANN_JSON=On -DUSE_BUNDLED_CXXOPTS=On -DUSE_BUNDLED_CPPHTTPLIB=On
- name: Build
run: |
pushd build
KERNELDIR=/lib/modules/$(uname -r)/build make -j4 all
popd
KERNELDIR=/lib/modules/$(uname -r)/build cmake --build build -j4
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9
uses: github/codeql-action/analyze@47b3d888fe66b639e431abf22ebca059152f1eea # v3.24.5

View File

@@ -31,13 +31,15 @@ jobs:
test-dev-packages:
needs: [fetch-version, build-dev-packages]
uses: ./.github/workflows/reusable_test_packages.yaml
strategy:
fail-fast: false
matrix:
static: ["static", ""]
# The musl build job is currently disabled because we link libelf dynamically and it is
# not possible to dynamically link with musl
# strategy:
# fail-fast: false
# matrix:
# static: ["static", ""]
with:
arch: x86_64
static: ${{ matrix.static != '' && true || false }}
# static: ${{ matrix.static != '' && true || false }}
version: ${{ needs.fetch-version.outputs.version }}
test-dev-packages-arm64:

View File

@@ -69,13 +69,16 @@ jobs:
test-packages:
needs: [release-settings, build-packages]
uses: ./.github/workflows/reusable_test_packages.yaml
strategy:
fail-fast: false
matrix:
static: ["static", ""]
# The musl build job is currently disabled because we link libelf dynamically and it is
# not possible to dynamically link with musl
# strategy:
# fail-fast: false
# matrix:
# static: ["static", ""]
with:
arch: x86_64
static: ${{ matrix.static != '' && true || false }}
# static: ${{ matrix.static != '' && true || false }}
version: ${{ github.event.release.tag_name }}
test-packages-arm64:
@@ -137,7 +140,7 @@ jobs:
run: |
cp .github/release_template.md release-body.md
LIBS_VERS=$(cat cmake/modules/falcosecurity-libs.cmake | grep 'set(FALCOSECURITY_LIBS_VERSION' | tail -n1 | grep -o '[[:digit:]]*\.[[:digit:]]*\.[[:digit:]]*')
DRIVER_VERS=$(cat cmake/modules/driver.cmake | grep 'set(DRIVER_VERSION' | tail -n1 | grep -o '[[:digit:]]*\.[[:digit:]]*\.[[:digit:]]*')
DRIVER_VERS=$(cat cmake/modules/driver.cmake | grep 'set(DRIVER_VERSION' | tail -n1 | grep -o '[[:digit:]]*\.[[:digit:]]*\.[[:digit:]]*+driver')
sed -i s/LIBSVER/$LIBS_VERS/g release-body.md
sed -i s/DRIVERVER/$DRIVER_VERS/g release-body.md
@@ -147,7 +150,7 @@ jobs:
sed -i s/FALCOVER/${{ github.event.release.tag_name }}/g release-body.md
- name: Generate release notes
uses: leodido/rn2md@0669e5f3b21492c11c2db43cd6e267566f5880f3
uses: leodido/rn2md@9c351d81278644c0e17b1ca68edbdba305276c73
with:
milestone: ${{ github.event.release.tag_name }}
output: ./notes.md

View File

@@ -14,6 +14,11 @@ on:
description: Minimal build
required: true
type: boolean
sanitizers:
description: Enable sanitizer support
required: false
default: false
type: boolean
build_type:
description: One of 'Debug' or 'Release'
required: true
@@ -27,14 +32,13 @@ 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@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
@@ -44,37 +48,38 @@ jobs:
- 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
pushd build
cmake \
cmake -B build -S .\
-DBUILD_FALCO_UNIT_TESTS=On \
-DCMAKE_BUILD_TYPE=${{ inputs.build_type }} \
-DBUILD_FALCO_MODERN_BPF=Off \
-DBUILD_BPF=${{ inputs.minimal == true && 'OFF' || 'ON' }} \
-DBUILD_DRIVER=${{ inputs.minimal == true && 'OFF' || 'ON' }} \
-DMINIMAL_BUILD=${{ inputs.minimal == true && 'ON' || 'OFF' }} \
..
popd
-DUSE_ASAN=${{ inputs.sanitizers == true && 'ON' || 'OFF' }} \
-DUSE_UBSAN=${{ inputs.sanitizers == true && 'ON' || 'OFF' }} \
-DUSE_BUNDLED_DEPS=Off \
-DUSE_BUNDLED_NLOHMANN_JSON=On \
-DUSE_BUNDLED_CXXOPTS=On \
-DUSE_BUNDLED_CPPHTTPLIB=On \
- name: Build
run: |
pushd build
KERNELDIR=/lib/modules/$(uname -r)/build make -j4 all
popd
KERNELDIR=/lib/modules/$(uname -r)/build cmake --build build -j4
- 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,7 +27,7 @@ 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:

View File

@@ -10,37 +10,47 @@ on:
description: The Falco version to use when building packages
required: true
type: string
build_type:
description: The build type
required: false
type: string
default: 'Release'
sanitizers:
description: enable sanitizer support
required: false
type: boolean
default: false
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.
- name: Install build dependencies
run: |
dnf install -y bpftool ca-certificates cmake make automake gcc gcc-c++ kernel-devel clang git pkg-config autoconf automake libbpf-devel
dnf install -y bpftool ca-certificates cmake make automake gcc gcc-c++ kernel-devel clang git pkg-config autoconf automake libbpf-devel elfutils-libelf-devel
- name: Checkout
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- name: Build modern BPF skeleton
run: |
mkdir skeleton-build && cd skeleton-build
cmake -DUSE_BUNDLED_DEPS=ON -DBUILD_FALCO_MODERN_BPF=ON -DCREATE_TEST_TARGETS=Off -DFALCO_VERSION=${{ inputs.version }} ..
make ProbeSkeleton -j6
cmake -B skeleton-build -S . \
-DUSE_BUNDLED_DEPS=ON -DCREATE_TEST_TARGETS=Off -DFALCO_VERSION=${{ inputs.version }}
cmake --build skeleton-build --target ProbeSkeleton -j6
- name: Upload skeleton
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
retention-days: 1
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:
@@ -50,77 +60,73 @@ jobs:
yum -y install centos-release-scl
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++
source /opt/rh/devtoolset-9/enable
yum install -y wget git make m4 rpm-build perl-IPC-Cmd
yum install -y wget git make m4 rpm-build elfutils-libelf-devel perl-IPC-Cmd devtoolset-9-libasan-devel devtoolset-9-libubsan-devel
- name: Checkout
# 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@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: bpf_probe_${{ inputs.arch }}.skel.h
path: /tmp
- name: Install updated cmake
run: |
curl -L -o /tmp/cmake.tar.gz https://github.com/Kitware/CMake/releases/download/v3.22.5/cmake-3.22.5-linux-$(uname -m).tar.gz
gzip -d /tmp/cmake.tar.gz
tar -xpf /tmp/cmake.tar --directory=/tmp
cp -R /tmp/cmake-3.22.5-linux-$(uname -m)/* /usr
rm -rf /tmp/cmake-3.22.5-linux-$(uname -m)
curl -L https://github.com/Kitware/CMake/releases/download/v3.22.5/cmake-3.22.5-linux-$(uname -m).tar.gz \
| tar --directory=/usr --strip-components=1 -xzp
- name: Prepare project
run: |
mkdir build && cd build
source /opt/rh/devtoolset-9/enable
cmake \
-DCMAKE_BUILD_TYPE=Release \
cmake -B build -S . \
-DCMAKE_BUILD_TYPE=${{ inputs.build_type }} \
-DUSE_BUNDLED_DEPS=On \
-DFALCO_ETC_DIR=/etc/falco \
-DBUILD_FALCO_MODERN_BPF=ON \
-DMODERN_BPF_SKEL_DIR=/tmp \
-DBUILD_DRIVER=Off \
-DBUILD_BPF=Off \
-DFALCO_VERSION=${{ inputs.version }} \
..
-DUSE_ASAN=${{ (inputs.sanitizers == true && inputs.arch == 'x86_64' && 'ON') || 'OFF' }} \
-DFALCO_VERSION=${{ inputs.version }}
- name: Build project
run: |
cd build
source /opt/rh/devtoolset-9/enable
make falco -j6
cmake --build build --target falco -j6
- name: Build packages
run: |
cd build
source /opt/rh/devtoolset-9/enable
make package
cmake --build build --target package
- name: Upload Falco tar.gz package
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: falco-${{ inputs.version }}-${{ inputs.arch }}.tar.gz
name: falco-${{ inputs.version }}-${{ inputs.arch }}${{ inputs.sanitizers == true && '-sanitizers' || '' }}.tar.gz
path: |
${{ github.workspace }}/build/falco-*.tar.gz
- name: Upload Falco deb package
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: falco-${{ inputs.version }}-${{ inputs.arch }}.deb
name: falco-${{ inputs.version }}-${{ inputs.arch }}${{ inputs.sanitizers == true && '-sanitizers' || '' }}.deb
path: |
${{ github.workspace }}/build/falco-*.deb
- name: Upload Falco rpm package
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: falco-${{ inputs.version }}-${{ inputs.arch }}.rpm
name: falco-${{ inputs.version }}-${{ inputs.arch }}${{ inputs.sanitizers == true && '-sanitizers' || '' }}.rpm
path: |
${{ github.workspace }}/build/falco-*.rpm
# The musl build job is currently disabled because we link libelf dynamically and it is
# not possible to dynamically link with musl
build-musl-package:
# x86_64 only for now
if: ${{ inputs.arch == 'x86_64' }}
# if: ${{ inputs.arch == 'x86_64' }}
if: false
runs-on: ubuntu-latest
container: alpine:3.17
steps:
@@ -128,32 +134,33 @@ jobs:
- name: Install build dependencies
run: |
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@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
fetch-depth: 0
- name: Prepare project
run: |
mkdir build && cd build
cmake -DCPACK_GENERATOR=TGZ -DBUILD_BPF=Off -DBUILD_DRIVER=Off -DCMAKE_BUILD_TYPE=Release -DUSE_BUNDLED_DEPS=On -DUSE_BUNDLED_LIBELF=Off -DBUILD_LIBSCAP_MODERN_BPF=ON -DMUSL_OPTIMIZED_BUILD=On -DFALCO_ETC_DIR=/etc/falco ../ -DFALCO_VERSION=${{ inputs.version }}
cmake -B build -S . \
-DCMAKE_BUILD_TYPE=${{ inputs.build_type }} \
-DCPACK_GENERATOR=TGZ \
-DBUILD_BPF=Off -DBUILD_DRIVER=Off \
-DUSE_BUNDLED_DEPS=On -DUSE_BUNDLED_LIBELF=Off -DBUILD_LIBSCAP_MODERN_BPF=ON -DMUSL_OPTIMIZED_BUILD=On -DFALCO_ETC_DIR=/etc/falco -DFALCO_VERSION=${{ inputs.version }}
- name: Build project
run: |
cd build
make -j6 all
cmake --build build -j6
- name: Build packages
run: |
cd build
make -j6 package
cmake --build build -j6 --target package
- name: Rename static package
run: |
cd build
mv falco-${{ inputs.version }}-x86_64.tar.gz falco-${{ inputs.version }}-static-x86_64.tar.gz
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@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
@@ -175,41 +182,39 @@ jobs:
uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
with:
node-version: 14
- name: Checkout
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
fetch-depth: 0
- name: Prepare project
run: |
mkdir build && cd build
emcmake cmake \
emcmake cmake -B build -S . \
-DBUILD_BPF=Off \
-DBUILD_DRIVER=Off \
-DBUILD_LIBSCAP_MODERN_BPF=OFF \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_FALCO_MODERN_BPF=Off \
-DCMAKE_BUILD_TYPE=${{ inputs.build_type }} \
-DUSE_BUNDLED_DEPS=On \
-DFALCO_ETC_DIR=/etc/falco \
-DBUILD_FALCO_UNIT_TESTS=On \
-DFALCO_VERSION=${{ inputs.version }} \
..
-DFALCO_VERSION=${{ inputs.version }}
- name: Build project
run: |
cd build
emmake make -j6 all
- name: Run unit Tests
run: |
cd build
node ./unit_tests/falco_unit_tests.js
- name: Build packages
run: |
cd build
emmake make -j6 package
- name: Upload Falco WASM package
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
@@ -226,19 +231,18 @@ jobs:
with:
fetch-depth: 0
# NOTE: Backslash doesn't work as line continuation on Windows.
- 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 }} ..
cmake -B build -S . -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -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
cmake --build build --target package --config ${{ inputs.build_type }}
- name: Run unit Tests
run: |
build/unit_tests/Release/falco_unit_tests.exe
build/unit_tests/${{ inputs.build_type }}/falco_unit_tests.exe
- name: Upload Falco win32 installer
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
@@ -251,7 +255,7 @@ jobs:
with:
name: falco-${{ inputs.version }}-win32.exe
path: |
${{ github.workspace }}/build/userspace/falco/Release/falco.exe
${{ github.workspace }}/build/userspace/falco/${{ inputs.build_type }}/falco.exe
build-macos-package:
if: ${{ inputs.arch == 'x86_64' }}
@@ -264,9 +268,8 @@ jobs:
- 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 }} ..
cmake -B build -S . \
-DMINIMAL_BUILD=On -DUSE_BUNDLED_DEPS=On -DBUILD_FALCO_UNIT_TESTS=On -DFALCO_VERSION=${{ inputs.version }}
- name: Build project
run: |

View File

@@ -5,34 +5,33 @@ on:
version:
description: "Falco version"
value: ${{ jobs.fetch-version.outputs.version }}
jobs:
# We need to use an ubuntu-latest to fetch Falco version because
# Falco version is computed by some cmake scripts that do git sorceries
# to get the current version.
# But centos7 jobs have a git version too old and actions/checkout does not
# But centos7 jobs have a git version too old and actions/checkout does not
# fully clone the repo, but uses http rest api instead.
fetch-version:
runs-on: ubuntu-latest
# Map the job outputs to step outputs
outputs:
version: ${{ steps.store_version.outputs.version }}
version: ${{ steps.store_version.outputs.version }}
steps:
- name: Checkout
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
fetch-depth: 0
- name: Install build dependencies
run: |
sudo apt update
sudo apt update
sudo apt install -y cmake build-essential
- name: Configure project
run: |
mkdir build && cd build
cmake -DUSE_BUNDLED_DEPS=On ..
cmake -B build -S . -DUSE_BUNDLED_DEPS=On -DUSE_DYNAMIC_LIBELF=Off
- name: Load and store Falco version output
id: store_version
run: |

View File

@@ -65,12 +65,21 @@ jobs:
name: falco-${{ inputs.version }}-aarch64.tar.gz
path: /tmp/falco-build-bin
# The musl build job is currently disabled because we link libelf dynamically and it is
# not possible to dynamically link with musl
- name: Download static binary x86_64
if: false
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: Download WASM package
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: falco-${{ inputs.version }}-wasm.tar.gz
path: /tmp/falco-wasm
- name: Import gpg key
env:
GPG_KEY: ${{ secrets.GPG_KEY }}
@@ -81,6 +90,10 @@ jobs:
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 wasm
run: |
./scripts/publish-wasm -f /tmp/falco-wasm/falco-${{ inputs.version }}-wasm.tar.gz
- 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 }}
@@ -89,11 +102,14 @@ jobs:
run: |
./scripts/publish-bin -f /tmp/falco-build-bin/falco-${{ inputs.version }}-x86_64.tar.gz -r bin${{ inputs.bucket_suffix }} -a x86_64
./scripts/publish-bin -f /tmp/falco-build-bin/falco-${{ inputs.version }}-aarch64.tar.gz -r bin${{ inputs.bucket_suffix }} -a aarch64
# The musl build job is currently disabled because we link libelf dynamically and it is
# not possible to dynamically link with musl
- name: Publish static
if: false
run: |
./scripts/publish-bin -f /tmp/falco-build-bin-static/falco-${{ inputs.version }}-static-x86_64.tar.gz -r bin${{ inputs.bucket_suffix }} -a x86_64
publish-packages-deb:
runs-on: ubuntu-latest
container: docker.io/debian:stable

View File

@@ -15,27 +15,21 @@ on:
description: The Falco version to use when testing packages
required: true
type: string
sanitizers:
description: Use sanitizer enabled build
required: false
default: false
type: boolean
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-latest' }}
steps:
- name: Checkout
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
fetch-depth: 0
submodules: 'true'
- name: Setup Go
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
with:
go-version: '>=1.17.0'
- name: Download binary
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
name: falco-${{ inputs.version }}${{ inputs.static && '-static' || '' }}-${{ inputs.arch }}.tar.gz
name: falco-${{ inputs.version }}${{ inputs.static && '-static' || '' }}-${{ inputs.arch }}${{ inputs.sanitizers == true && '-sanitizers' || '' }}.tar.gz
- name: Install Falco package
run: |
@@ -43,48 +37,28 @@ 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
# We only run driver loader tests on x86_64
- name: Install kernel headers for falco-driver-loader tests
if: ${{ inputs.arch == 'x86_64' }}
run: |
sudo apt update -y
sudo apt install -y --no-install-recommends build-essential clang make llvm gcc dkms linux-headers-$(uname -r)
sudo apt install -y --no-install-recommends linux-headers-$(uname -r)
- name: Install go-junit-report
# Some builds use sanitizers, we always install support for them so they can run
- name: Install sanitizer support
run: |
pushd submodules/falcosecurity-testing
go install github.com/jstemmer/go-junit-report/v2@latest
popd
- name: Generate regression test files
run: |
pushd submodules/falcosecurity-testing
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
sudo apt update -y
sudo apt install -y libasan5 libubsan1
- name: Run tests
env:
# fixme(leogr): this is a workaround for https://github.com/falcosecurity/falco/issues/2784
HOST_ROOT: ""
run: |
pushd submodules/falcosecurity-testing
./build/falco.test -falco-static=${{ inputs.static && 'true' || 'false' }} -test.timeout=90s -test.v >> ./report.txt 2>&1 || true
if ${{ inputs.static && 'false' || 'true' }}; then
./build/falcoctl.test -test.timeout=90s -test.v >> ./report.txt 2>&1 || true
./build/k8saudit.test -test.timeout=90s -test.v >> ./report.txt 2>&1 || true
if ${{ inputs.arch == 'x86_64' && 'true' || 'false' }}; then
sudo ./build/falco-driver-loader.test -test.timeout=90s -test.v >> ./report.txt 2>&1 || true
fi
fi
cat ./report.txt | go-junit-report -set-exit-code > report.xml
popd
- name: Test Summary
if: always() # run this even if previous step fails
uses: test-summary/action@62bc5c68de2a6a0d02039763b8c754569df99e3f # v2.1
LSAN_OPTIONS: "intercept_tls_get_addr=0"
uses: falcosecurity/testing@main
with:
paths: "submodules/falcosecurity-testing/report.xml"
show: "fail"
test-falco: 'true'
test-falcoctl: 'true'
test-k8saudit: 'true'
static: ${{ inputs.static && 'true' || 'false' }}
test-drivers: ${{ inputs.arch == 'x86_64' && 'true' || 'false' }}
show-all: 'true'

View File

@@ -43,7 +43,7 @@ jobs:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@e38b1902ae4f44df626f11ba0734b14fb91f8f86 # v2.1.2
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
with:
results_file: results.sarif
results_format: sarif

View File

@@ -19,10 +19,11 @@ jobs:
- name: Build and run cppcheck 🏎️
run: |
mkdir build
cd build && cmake -DUSE_BUNDLED_DEPS=On -DBUILD_WARNINGS_AS_ERRORS=ON -DCREATE_TEST_TARGETS=Off -DCMAKE_BUILD_TYPE="release" -DBUILD_BPF=Off -DBUILD_DRIVER=Off ..
make -j4 cppcheck
make -j4 cppcheck_htmlreport
cmake -B build -S . \
-DCMAKE_BUILD_TYPE="release" \
-DUSE_BUNDLED_DEPS=On -DUSE_DYNAMIC_LIBELF=Off -DBUILD_WARNINGS_AS_ERRORS=ON -DCREATE_TEST_TARGETS=Off -DBUILD_BPF=Off -DBUILD_DRIVER=Off
cmake --build build -j4 --target cppcheck
cmake --build build -j4 --target cppcheck_htmlreport
- name: Upload reports ⬆️
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3

1
.gitignore vendored
View File

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

4
.gitmodules vendored
View File

@@ -2,7 +2,3 @@
path = submodules/falcosecurity-rules
url = https://github.com/falcosecurity/rules.git
branch = main
[submodule "submodules/falcosecurity-testing"]
path = submodules/falcosecurity-testing
url = https://github.com/falcosecurity/testing.git
branch = main

View File

@@ -1,5 +1,159 @@
# Change Log
## v0.37.1
Released on 2024-02-13
### Major Changes
* new(docker): added option for insecure http driver download to falco and driver-loader images [[#3058](https://github.com/falcosecurity/falco/pull/3058)] - [@toamto94](https://github.com/toamto94)
### Minor Changes
* update(cmake): bumped falcoctl to v0.7.2 [[#3076](https://github.com/falcosecurity/falco/pull/3076)] - [@FedeDP](https://github.com/FedeDP)
* update(build): link libelf dynamically [[#3048](https://github.com/falcosecurity/falco/pull/3048)] - [@LucaGuerra](https://github.com/LucaGuerra)
### Bug Fixes
* fix(userspace/engine): always consider all rules (even the ones below min_prio) in m_rule_stats_manager [[#3060](https://github.com/falcosecurity/falco/pull/3060)] - [@FedeDP](https://github.com/FedeDP)
### Non user-facing changes
* Added http headers option for driver download in docker images [[#3075](https://github.com/falcosecurity/falco/pull/3075)] - [@toamto94](https://github.com/toamto94)
* fix(build): install libstdc++ in the Wolfi image [[#3053](https://github.com/falcosecurity/falco/pull/3053)] - [@LucaGuerra](https://github.com/LucaGuerra)
## v0.37.0
Released on 2024-01-30
### Breaking Changes
- The deprecated `rate-limiter` mechanism is removed as it is no longer used.
- the deprecated `outputs.rate` Falco config is removed.
- the deprecated `outputs.max_burst` Falco config is removed.
- The deprecated `--userspace` CLI option is removed as it is no longer used.
- The `falco-driver-loader` script will be removed and embedded into falcoctl. The new falcoctl driven implementation will drop:
- `--source-only` CLI option.
- `BPF_USE_LOCAL_KERNEL_SOURCES` environment variable.
- `DRIVER_CURL_OPTIONS` environment variable.
- `FALCO_BPF_PROBE` environment variable is not used by the new falcoctl driver loader, since it is already deprecated and will be removed in the next major version.
Some env vars were renamed:
- `DRIVERS_REPO` env variable has been replaced by `FALCOCTL_DRIVER_NAME` or `--name` command line argument for `falcoctl driver` command
- `DRIVERS_NAME` env variable has been replaced by `FALCOCTL_DRIVER_REPOS`, or `--repo` command line argument for `falcoctl driver` command
- `DRIVER_KERNEL_RELEASE` env variable has been replaced by `--kernelrelease` command line argument for `falcoctl driver install` command
- `DRIVER_KERNEL_VERSION` env variable has been replaced by `--kernelversion` command line argument for `falcoctl driver install` command
- `DRIVER_INSECURE_DOWNLOAD` env variable has been replaced by `--http-insecure` command line argument for `falcoctl driver install` command
- Remove `-K/-k` options from Falco in favor of the new `k8smeta` plugin.
- Drop plugins shipped with Falco since plugins are now be managed by falcoctl.
- Falco 0.37.0 allows environment variables to be expanded even if they are part of a string. This introduces small breaking changes:
- Previously, environment variables used in YAML that were empty or defined as `“”` would be expanded to the default value. This was not consistent with the way YAML was handled in other cases, where we only returned the default values if the node was not defined. Now expanded env vars retain the same behavior of all other variables.
- Falco 0.37.0 will return default value for nodes that cannot be parsed to chosen type.
- `program_output` command will be env-expanded at init time, instead of letting `popen` and thus the `sh` shell expand it. This is technically a breaking change even if no behavioral change is expected. Also, you can avoid env var expansion by using `${{FOO}}` instead of `${FOO}`. It will resolve to `${FOO}` and won't be resolved to the env var value.
### Major Changes
* new!: dropped falco-driver-loader script in favor of new falcoctl driver command [[#2905](https://github.com/falcosecurity/falco/pull/2905)] - [@FedeDP](https://github.com/FedeDP)
* update!: bump libs to latest and deprecation of k8s metadata options and configs [[#2914](https://github.com/falcosecurity/falco/pull/2914)] - [@jasondellaluce](https://github.com/jasondellaluce)
* cleanup(falco)!: remove `outputs.rate` and `outputs.max_burst` from Falco config [[#2841](https://github.com/falcosecurity/falco/pull/2841)] - [@Andreagit97](https://github.com/Andreagit97)
* cleanup(falco)!: remove `--userspace` support [[#2839](https://github.com/falcosecurity/falco/pull/2839)] - [@Andreagit97](https://github.com/Andreagit97)
* new(engine): add selective overrides for Falco rules [[#2981](https://github.com/falcosecurity/falco/pull/2981)] - [@LucaGuerra](https://github.com/LucaGuerra)
* feat(userspace/falco): falco administrators can now configure the http output to compress the data sent as well as enable keep alive for the connection. Two new fields (compress_uploads and keep_alive) in the http_output block of the `falco.yaml` file can be used for that purpose. Both are disabled by default. [[#2974](https://github.com/falcosecurity/falco/pull/2974)] - [@sgaist](https://github.com/sgaist)
* new(userspace): support env variable expansion in all yaml, even inside strings. [[#2918](https://github.com/falcosecurity/falco/pull/2918)] - [@FedeDP](https://github.com/FedeDP)
* new(scripts): add a way to enforce driver kind and falcoctl enablement when installing Falco from packages and dialog is not present. [[#2773](https://github.com/falcosecurity/falco/pull/2773)] - [@vjjmiras](https://github.com/vjjmiras)
* new(falco): print system info when Falco starts [[#2927](https://github.com/falcosecurity/falco/pull/2927)] - [@Andreagit97](https://github.com/Andreagit97)
* new: driver selection in falco.yaml [[#2413](https://github.com/falcosecurity/falco/pull/2413)] - [@therealbobo](https://github.com/therealbobo)
* new(build): enable compilation on win32 and macOS. [[#2889](https://github.com/falcosecurity/falco/pull/2889)] - [@therealbobo](https://github.com/therealbobo)
* feat(userspace/falco): falco administrators can now configure the address on which the webserver listen using the new listen_address field in the webserver block of the `falco.yaml` file. [[#2890](https://github.com/falcosecurity/falco/pull/2890)] - [@sgaist](https://github.com/sgaist)
### Minor Changes
* update(userspace/falco): add `engine_version_semver` key in `/versions` endpoint [[#2899](https://github.com/falcosecurity/falco/pull/2899)] - [@loresuso](https://github.com/loresuso)
* update: default ruleset upgrade to version 3.0 [[#3034](https://github.com/falcosecurity/falco/pull/3034)] - [@leogr](https://github.com/leogr)
* update!(config): soft deprecation of drop stats counters in `syscall_event_drops` [[#3015](https://github.com/falcosecurity/falco/pull/3015)] - [@incertum](https://github.com/incertum)
* update(cmake): bumped falcoctl tool to v0.7.1. [[#3030](https://github.com/falcosecurity/falco/pull/3030)] - [@FedeDP](https://github.com/FedeDP)
* update(rule_loader): deprecate the `append` flag in Falco rules [[#2992](https://github.com/falcosecurity/falco/pull/2992)] - [@Andreagit97](https://github.com/Andreagit97)
* cleanup!(cmake): drop bundled plugins in Falco [[#2997](https://github.com/falcosecurity/falco/pull/2997)] - [@FedeDP](https://github.com/FedeDP)
* update(config): clarify deprecation notices + list all env vars [[#2988](https://github.com/falcosecurity/falco/pull/2988)] - [@incertum](https://github.com/incertum)
* update: now the `watch_config_files` config option monitors file/directory moving and deletion, too [[#2965](https://github.com/falcosecurity/falco/pull/2965)] - [@NitroCao](https://github.com/NitroCao)
* update(userspace): enhancements in rule description feature [[#2934](https://github.com/falcosecurity/falco/pull/2934)] - [@jasondellaluce](https://github.com/jasondellaluce)
* update(userspace/falco): add libsinsp state metrics option [[#2883](https://github.com/falcosecurity/falco/pull/2883)] - [@incertum](https://github.com/incertum)
* update(doc): Add Thought Machine as adopters [[#2919](https://github.com/falcosecurity/falco/pull/2919)] - [@RichardoC](https://github.com/RichardoC)
* update(docs): add Wireshark/Logray as adopter [[#2867](https://github.com/falcosecurity/falco/pull/2867)] - [@geraldcombs](https://github.com/geraldcombs)
* update: engine_version in semver representation [[#2838](https://github.com/falcosecurity/falco/pull/2838)] - [@loresuso](https://github.com/loresuso)
* update(userspace/engine): modularize rule compiler, fix and enrich rule descriptions [[#2817](https://github.com/falcosecurity/falco/pull/2817)] - [@jasondellaluce](https://github.com/jasondellaluce)
### Bug Fixes
* fix(userspace/metric): minor fixes in new libsinsp state metrics handling [[#3033](https://github.com/falcosecurity/falco/pull/3033)] - [@incertum](https://github.com/incertum)
* fix(userspace/engine): avoid storing escaped strings in engine defs [[#3028](https://github.com/falcosecurity/falco/pull/3028)] - [@jasondellaluce](https://github.com/jasondellaluce)
* fix(userspace/engine): cache latest rules compilation output [[#2900](https://github.com/falcosecurity/falco/pull/2900)] - [@jasondellaluce](https://github.com/jasondellaluce)
* fix(userspace/engine): solve description of macro-only rules [[#2898](https://github.com/falcosecurity/falco/pull/2898)] - [@jasondellaluce](https://github.com/jasondellaluce)
* fix(userspace/engine): fix memory leak [[#2877](https://github.com/falcosecurity/falco/pull/2877)] - [@therealbobo](https://github.com/therealbobo)
### Non user-facing changes
* fix: nlohmann_json lib include path [[#3032](https://github.com/falcosecurity/falco/pull/3032)] - [@federico-sysdig](https://github.com/federico-sysdig)
* chore: bump falco rules [[#3021](https://github.com/falcosecurity/falco/pull/3021)] - [@Andreagit97](https://github.com/Andreagit97)
* chore: bump Falco to libs 0.14.1 [[#3020](https://github.com/falcosecurity/falco/pull/3020)] - [@Andreagit97](https://github.com/Andreagit97)
* chore(build): remove outdated development libs [[#2946](https://github.com/falcosecurity/falco/pull/2946)] - [@federico-sysdig](https://github.com/federico-sysdig)
* chore(falco): bump Falco to `000d576` libs commit [[#2944](https://github.com/falcosecurity/falco/pull/2944)] - [@Andreagit97](https://github.com/Andreagit97)
* fix(gha): update rpmsign [[#2856](https://github.com/falcosecurity/falco/pull/2856)] - [@LucaGuerra](https://github.com/LucaGuerra)
* build(deps): Bump submodules/falcosecurity-rules from `424b258` to `1221b9e` [[#3000](https://github.com/falcosecurity/falco/pull/3000)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* build(deps): Bump submodules/falcosecurity-rules from `2ac430b` to `c39d31a` [[#3019](https://github.com/falcosecurity/falco/pull/3019)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* cleanup(falco.yaml): rename `none` in `nodriver` [[#3012](https://github.com/falcosecurity/falco/pull/3012)] - [@Andreagit97](https://github.com/Andreagit97)
* update(config): graduate outputs_queue to stable [[#3016](https://github.com/falcosecurity/falco/pull/3016)] - [@incertum](https://github.com/incertum)
* update(cmake): bump falcoctl to v0.7.0. [[#3009](https://github.com/falcosecurity/falco/pull/3009)] - [@FedeDP](https://github.com/FedeDP)
* build(deps): Bump submodules/falcosecurity-rules from `1221b9e` to `2ac430b` [[#3007](https://github.com/falcosecurity/falco/pull/3007)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* chore(ci): bumped rn2md to latest master. [[#3006](https://github.com/falcosecurity/falco/pull/3006)] - [@FedeDP](https://github.com/FedeDP)
* chore: bump Falco to latest libs [[#3002](https://github.com/falcosecurity/falco/pull/3002)] - [@Andreagit97](https://github.com/Andreagit97)
* chore: bump driver version [[#2998](https://github.com/falcosecurity/falco/pull/2998)] - [@Andreagit97](https://github.com/Andreagit97)
* Add addl source related methods [[#2939](https://github.com/falcosecurity/falco/pull/2939)] - [@mstemm](https://github.com/mstemm)
* build(deps): Bump submodules/falcosecurity-rules from `cd33bc3` to `424b258` [[#2993](https://github.com/falcosecurity/falco/pull/2993)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* cleanup(engine): clarify deprecation notice for engines [[#2987](https://github.com/falcosecurity/falco/pull/2987)] - [@LucaGuerra](https://github.com/LucaGuerra)
* update(cmake): bumped falcoctl to v0.7.0-rc1. [[#2983](https://github.com/falcosecurity/falco/pull/2983)] - [@FedeDP](https://github.com/FedeDP)
* chore(ci): revert #2961. [[#2984](https://github.com/falcosecurity/falco/pull/2984)] - [@FedeDP](https://github.com/FedeDP)
* build(deps): Bump submodules/falcosecurity-testing from `930170b` to `9b9630e` [[#2980](https://github.com/falcosecurity/falco/pull/2980)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* chore: bump Falco to latest libs [[#2977](https://github.com/falcosecurity/falco/pull/2977)] - [@Andreagit97](https://github.com/Andreagit97)
* build(deps): Bump submodules/falcosecurity-rules from `262f569` to `cd33bc3` [[#2976](https://github.com/falcosecurity/falco/pull/2976)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* Allow enabling rules by ruleset id in addition to name [[#2920](https://github.com/falcosecurity/falco/pull/2920)] - [@mstemm](https://github.com/mstemm)
* chore(ci): enable aarch64 falco driver loader tests. [[#2961](https://github.com/falcosecurity/falco/pull/2961)] - [@FedeDP](https://github.com/FedeDP)
* chore(unit_tests): added more tests for yaml env vars expansion. [[#2972](https://github.com/falcosecurity/falco/pull/2972)] - [@FedeDP](https://github.com/FedeDP)
* chore(falco.yaml): use HOME env var for ebpf probe path. [[#2971](https://github.com/falcosecurity/falco/pull/2971)] - [@FedeDP](https://github.com/FedeDP)
* chore: bump falco to latest libs [[#2970](https://github.com/falcosecurity/falco/pull/2970)] - [@Andreagit97](https://github.com/Andreagit97)
* build(deps): Bump submodules/falcosecurity-rules from `dd38952` to `262f569` [[#2969](https://github.com/falcosecurity/falco/pull/2969)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* update(readme): add actuated.dev badge [[#2967](https://github.com/falcosecurity/falco/pull/2967)] - [@LucaGuerra](https://github.com/LucaGuerra)
* chore(cmake,docker): bumped falcoctl to v0.7.0-beta5. [[#2968](https://github.com/falcosecurity/falco/pull/2968)] - [@FedeDP](https://github.com/FedeDP)
* build(deps): Bump submodules/falcosecurity-rules from `64e2adb` to `dd38952` [[#2959](https://github.com/falcosecurity/falco/pull/2959)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* fix(docker): small fixes in docker entrypoints for new driver loader. [[#2966](https://github.com/falcosecurity/falco/pull/2966)] - [@FedeDP](https://github.com/FedeDP)
* chore(build): allow usage of non-bundled nlohmann-json [[#2947](https://github.com/falcosecurity/falco/pull/2947)] - [@federico-sysdig](https://github.com/federico-sysdig)
* update(ci): enable actuated.dev [[#2945](https://github.com/falcosecurity/falco/pull/2945)] - [@LucaGuerra](https://github.com/LucaGuerra)
* cleanup: fix several warnings from a Clang build [[#2948](https://github.com/falcosecurity/falco/pull/2948)] - [@federico-sysdig](https://github.com/federico-sysdig)
* chore(docker/falco): add back some deps to falco docker image. [[#2932](https://github.com/falcosecurity/falco/pull/2932)] - [@FedeDP](https://github.com/FedeDP)
* build(deps): Bump submodules/falcosecurity-testing from `92c313f` to `5248e6d` [[#2937](https://github.com/falcosecurity/falco/pull/2937)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* build(deps): Bump submodules/falcosecurity-rules from `e206c1a` to `8f0520f` [[#2904](https://github.com/falcosecurity/falco/pull/2904)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* cleanup(falco): remove decode_uri as it is no longer used [[#2933](https://github.com/falcosecurity/falco/pull/2933)] - [@LucaGuerra](https://github.com/LucaGuerra)
* update(engine): port decode_uri in falco engine [[#2912](https://github.com/falcosecurity/falco/pull/2912)] - [@LucaGuerra](https://github.com/LucaGuerra)
* chore(falco): update to libs on nov 28th [[#2929](https://github.com/falcosecurity/falco/pull/2929)] - [@LucaGuerra](https://github.com/LucaGuerra)
* cleanup(falco): remove `init` in the configuration constructor [[#2917](https://github.com/falcosecurity/falco/pull/2917)] - [@Andreagit97](https://github.com/Andreagit97)
* build(deps): Bump submodules/falcosecurity-rules from `8f0520f` to `64e2adb` [[#2908](https://github.com/falcosecurity/falco/pull/2908)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* cleanup(userspace/engine): remove legacy k8saudit implementation [[#2913](https://github.com/falcosecurity/falco/pull/2913)] - [@jasondellaluce](https://github.com/jasondellaluce)
* fix(gha): disable branch protection rule trigger for scorecard [[#2911](https://github.com/falcosecurity/falco/pull/2911)] - [@LucaGuerra](https://github.com/LucaGuerra)
* chore(gha): set cosign-installer to v3.1.2 [[#2901](https://github.com/falcosecurity/falco/pull/2901)] - [@LucaGuerra](https://github.com/LucaGuerra)
* new(docs): sync changelog for 0.36.2. [[#2894](https://github.com/falcosecurity/falco/pull/2894)] - [@FedeDP](https://github.com/FedeDP)
* Run OpenSSF Scorecard in pipeline [[#2888](https://github.com/falcosecurity/falco/pull/2888)] - [@maxgio92](https://github.com/maxgio92)
* cleanup: replace banned.h with semgrep [[#2881](https://github.com/falcosecurity/falco/pull/2881)] - [@LucaGuerra](https://github.com/LucaGuerra)
* chore(gha): upgrade GitHub actions [[#2876](https://github.com/falcosecurity/falco/pull/2876)] - [@LucaGuerra](https://github.com/LucaGuerra)
* build(deps): Bump submodules/falcosecurity-rules from `a22d0d7` to `e206c1a` [[#2865](https://github.com/falcosecurity/falco/pull/2865)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* build(deps): Bump submodules/falcosecurity-rules from `d119706` to `a22d0d7` [[#2860](https://github.com/falcosecurity/falco/pull/2860)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* fix(gha): use fedora instead of centos 7 for package publishing [[#2854](https://github.com/falcosecurity/falco/pull/2854)] - [@LucaGuerra](https://github.com/LucaGuerra)
* chore(gha): pin versions to hashes [[#2849](https://github.com/falcosecurity/falco/pull/2849)] - [@LucaGuerra](https://github.com/LucaGuerra)
* build(deps): Bump submodules/falcosecurity-rules from `c366d5b` to `d119706` [[#2847](https://github.com/falcosecurity/falco/pull/2847)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* new(ci): properly link libs and driver releases linked to a Falco release [[#2846](https://github.com/falcosecurity/falco/pull/2846)] - [@FedeDP](https://github.com/FedeDP)
* build(deps): Bump submodules/falcosecurity-rules from `7a7cf24` to `c366d5b` [[#2842](https://github.com/falcosecurity/falco/pull/2842)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* build(deps): Bump submodules/falcosecurity-rules from `77ba57a` to `7a7cf24` [[#2836](https://github.com/falcosecurity/falco/pull/2836)] - [@dependabot[bot]](https://github.com/apps/dependabot)
* chore(ci): bumped rn2md to latest master. [[#2844](https://github.com/falcosecurity/falco/pull/2844)] - [@FedeDP](https://github.com/FedeDP)
## v0.36.2
Released on 2023-10-27

View File

@@ -15,13 +15,22 @@ cmake_minimum_required(VERSION 3.5.1)
project(falco)
option(USE_BUNDLED_DEPS "Bundle hard to find dependencies into the Falco binary" OFF)
option(USE_BUNDLED_DEPS "Bundle hard to find dependencies into the Falco binary" ON)
option(USE_DYNAMIC_LIBELF "Dynamically link libelf" ON)
option(BUILD_WARNINGS_AS_ERRORS "Enable building with -Wextra -Werror flags" OFF)
option(MINIMAL_BUILD "Build a minimal version of Falco, containing only the engine and basic input/output (EXPERIMENTAL)" OFF)
option(MUSL_OPTIMIZED_BUILD "Enable if you want a musl optimized build" OFF)
option(BUILD_FALCO_UNIT_TESTS "Build falco unit tests" OFF)
option(USE_ASAN "Build with AddressSanitizer" OFF)
option(USE_UBSAN "Build with UndefinedBehaviorSanitizer" OFF)
option(UBSAN_HALT_ON_ERROR "Halt on error when building with UBSan" ON)
if(WIN32)
if(POLICY CMP0091)
# Needed for CMAKE_MSVC_RUNTIME_LIBRARY
# https://cmake.org/cmake/help/latest/policy/CMP0091.html
cmake_policy(SET CMP0091 NEW)
endif()
set(CPACK_GENERATOR "NSIS") # this needs NSIS installed, and available
elseif (APPLE)
set(CPACK_GENERATOR "DragNDrop")
@@ -43,7 +52,7 @@ endif()
# Modern BPF is not supported on not Linux systems and in MINIMAL_BUILD
if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT MINIMAL_BUILD)
option(BUILD_FALCO_MODERN_BPF "Build modern BPF support for Falco" OFF)
option(BUILD_FALCO_MODERN_BPF "Build modern BPF support for Falco" ON)
if(BUILD_FALCO_MODERN_BPF)
add_definitions(-DHAS_MODERN_BPF)
endif()
@@ -155,12 +164,15 @@ endif()
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}")
install(DIRECTORY DESTINATION etc/falco/config.d 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}")
install(DIRECTORY DESTINATION etc/falco/config.d 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}")
install(DIRECTORY DESTINATION "${FALCO_ETC_DIR}/config.d" COMPONENT "${FALCO_COMPONENT_NAME}")
endif()
if(NOT MINIMAL_BUILD)
@@ -178,9 +190,7 @@ include(rules)
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)
@@ -189,7 +199,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)
@@ -10,15 +10,15 @@
At its core, Falco is a kernel monitoring and detection agent that observes events, such as syscalls, based on custom rules. Falco can enhance these events by integrating metadata from the container runtime and Kubernetes. The collected events can be analyzed off-host in SIEM or data lake systems.
Falco, originally created by [Sysdig](https://sysdig.com), is an incubating project under the [Cloud Native Computing Foundation](https://cncf.io) (CNCF) used in production by various [organisations](https://github.com/falcosecurity/falco/blob/master/ADOPTERS.md).
Falco, originally created by [Sysdig](https://sysdig.com), is a **graduated project** under the [Cloud Native Computing Foundation](https://cncf.io) (CNCF) used in production by various [organisations](https://github.com/falcosecurity/falco/blob/master/ADOPTERS.md).
For detailed technical information and insights into the cyber threats that Falco can detect, visit the official [Falco](https://falco.org/) website.
For comprehensive information on the latest updates and changes to the project, please refer to the [change log](CHANGELOG.md). Additionally, we have documented the [release process](RELEASE.md) for delivering new versions of Falco.
For comprehensive information on the latest updates and changes to the project, please refer to the [Change Log](CHANGELOG.md). Additionally, we have documented the [Release Process](RELEASE.md) for delivering new versions of Falco.
## Falco Repo: Powering the Core of The Falco Project
This is the main Falco repository which contains the source code for building the Falco binary. By utilizing its [libraries](https://github.com/falcosecurity/libs) and the [falco.yaml](falco.yaml) configuration file, this repository forms the foundation of Falco's functionality. The Falco repository is closely interconnected with the following *core* repositories:
This is the main Falco repository which contains the source code for building the Falco binary. By utilizing its [libs](https://github.com/falcosecurity/libs) and the [falco.yaml](falco.yaml) configuration file, this repository forms the foundation of Falco's functionality. The Falco repository is closely interconnected with the following *core* repositories:
- [falcosecurity/libs](https://github.com/falcosecurity/libs): Falco's libraries are key to its fundamental operations, making up the greater portion of the source code of the Falco binary and providing essential features such as kernel drivers.
- [falcosecurity/rules](https://github.com/falcosecurity/rules): Contains the official ruleset for Falco, providing pre-defined detection rules for various security threats and abnormal behaviors.
@@ -29,7 +29,7 @@ For more information, visit the official hub of The Falco Project: [falcosecurit
## Getting Started with Falco
Carefully review and follow the [official guide and documentation](https://falco.org/docs/getting-started/).
Carefully review and follow the [Official Documentation](https://falco.org/docs/install-operate/).
Considerations and guidance for Falco adopters:
@@ -46,11 +46,11 @@ Considerations and guidance for Falco adopters:
## How to Contribute
Please refer to the [contributing guide](https://github.com/falcosecurity/.github/blob/main/CONTRIBUTING.md) and the [code of conduct](https://github.com/falcosecurity/evolution/blob/main/CODE_OF_CONDUCT.md) for more information on how to contribute.
Please refer to the [Contributing](https://github.com/falcosecurity/.github/blob/main/CONTRIBUTING.md) guide and the [Code of Conduct](https://github.com/falcosecurity/evolution/blob/main/CODE_OF_CONDUCT.md) for more information on how to contribute.
## Join the Community
To get involved with the Falco Project please visit the [community repository](https://github.com/falcosecurity/community) to find more information and ways to get involved.
To get involved with the Falco Project please visit the [Community](https://github.com/falcosecurity/community) repository to find more information and ways to get involved.
If you have any questions about Falco or contributing, do not hesitate to file an issue or contact the Falco maintainers and community members for assistance.
@@ -64,7 +64,7 @@ How to reach out?
Full reports of various security audits can be found [here](./audits/).
In addition, you can refer to the [falco security](https://github.com/falcosecurity/falco/security) and [libs security](https://github.com/falcosecurity/libs/security) sections for detailed updates on security advisories and policies.
In addition, you can refer to the [falco](https://github.com/falcosecurity/falco/security) and [libs](https://github.com/falcosecurity/libs/security) security sections for detailed updates on security advisories and policies.
To report security vulnerabilities, please follow the community process outlined in the documentation found [here](https://github.com/falcosecurity/.github/blob/main/SECURITY.md).
@@ -76,8 +76,49 @@ Stay updated with Falco's evolving capabilities by exploring the [Falco Roadmap]
Falco is licensed to you under the [Apache 2.0](./COPYING) open source license.
## Testing
<details>
<summary>Expand Testing Instructions</summary>
Falco's [Build Falco from source](https://falco.org/docs/install-operate/source/) is the go-to resource to understand how to build Falco from source. In addition, the [falcosecurity/libs](https://github.com/falcosecurity/libs) repository offers additional valuable information about tests and debugging of Falco's underlying libraries and kernel drivers.
Here's an example of a `cmake` command that will enable everything you need for all unit tests of this repository:
```bash
cmake \
-DUSE_BUNDLED_DEPS=ON \
-DBUILD_LIBSCAP_GVISOR=ON \
-DBUILD_BPF=ON \
-DBUILD_DRIVER=ON \
-DBUILD_FALCO_MODERN_BPF=ON \
-DCREATE_TEST_TARGETS=ON \
-DBUILD_FALCO_UNIT_TESTS=ON ..;
```
Build and run the unit test suite:
```bash
nproc=$(grep processor /proc/cpuinfo | tail -n 1 | awk '{print $3}');
make -j$(($nproc-1)) falco_unit_tests;
# Run the tests
sudo ./unit_tests/falco_unit_tests;
```
Optionally, build the driver of your choice and test run the Falco binary to perform manual tests.
Lastly, The Falco Project has moved its Falco regression tests to [falcosecurity/testing](https://github.com/falcosecurity/testing).
</details>
</br>
## Why is Falco in C++ rather than Go or {language}?
<details>
<summary>Expand Information</summary>
1. The first lines of code at the base of Falco were written some time ago, where Go didn't yet have the same level of maturity and adoption as today.
2. The Falco execution model is sequential and mono-thread due to the statefulness requirements of the tool, and so most of the concurrency-related selling points of the Go runtime would not be leveraged at all.
3. The Falco code deals with very low-level programming in many places (e.g. some headers are shared with the eBPF probe and the Kernel module), and we all know that interfacing Go with C is possible but brings tons of complexity and tradeoffs to the table.
@@ -89,6 +130,8 @@ Falco is licensed to you under the [Apache 2.0](./COPYING) open source license.
9. Memory safety is definitely a concern and we try our best to keep an high level of quality even though C++ is quite error prone. For instance, we try to use smart pointers whenever possible, we build the libraries with an address sanitizer in our CI, we run Falco through Valgrind before each release, and have ways to stress-test it to detect performance regressions or weird memory usage (e.g. https://github.com/falcosecurity/event-generator). On top of that, we also have third parties auditing the codebase by time to time. None of this make a perfect safety standpoint of course, but we try to maximize our odds. Go would definitely make our life easier from this perspective, however the tradeoffs never made it worth it so far due to the points above.
10. The C++ codebase of falcosecurity/libs, which is at the core of Falco, is quite large and complex. Porting all that code to another language would be a major effort requiring lots of development resource and with an high chance of failure and regression. As such, our approach so far has been to choose refactors and code polishing instead, up until we'll reach an optimal level of stability, quality, and modularity, on that portion of code. This would allow further developments to be smoother and more feasibile in the future.
</details>
</br>
## Resources
@@ -99,3 +142,5 @@ Falco is licensed to you under the [Apache 2.0](./COPYING) open source license.
- [Repositories Guidelines](https://github.com/falcosecurity/evolution/blob/main/REPOSITORIES.md)
- [Repositories List](https://github.com/falcosecurity/evolution/blob/main/README.md#repositories)
- [Adopters List](https://github.com/falcosecurity/falco/blob/master/ADOPTERS.md)
- [Install and Operate](https://falco.org/docs/install-operate/)
- [Troubleshooting](https://falco.org/docs/troubleshooting/)

View File

@@ -44,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

@@ -42,7 +42,8 @@ endif()
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")
set(FALCO_SECURITY_FLAGS "${FALCO_SECURITY_FLAGS} -fstack-protector-strong")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,relro,-z,now")
endif()
@@ -52,17 +53,29 @@ if(NOT MSVC)
set(FALCO_SECURITY_FLAGS "${FALCO_SECURITY_FLAGS} -D_FORTIFY_SOURCE=2")
endif()
if(USE_ASAN)
set(FALCO_SECURITY_FLAGS "${FALCO_SECURITY_FLAGS} -fsanitize=address")
endif()
if(USE_UBSAN)
set(FALCO_SECURITY_FLAGS "${FALCO_SECURITY_FLAGS} -fsanitize=undefined")
if(UBSAN_HALT_ON_ERROR)
set(FALCO_SECURITY_FLAGS "${FALCO_SECURITY_FLAGS} -fno-sanitize-recover=undefined")
endif()
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}")
set(CMAKE_COMPILE_WARNING_AS_ERROR ON)
set(CMAKE_COMMON_FLAGS "${CMAKE_COMMON_FLAGS} -Wextra ${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_CXX_FLAGS "-std=c++17 ${CMAKE_COMMON_FLAGS}")
set(CMAKE_C_FLAGS_DEBUG "${FALCO_EXTRA_DEBUG_FLAGS}")
set(CMAKE_CXX_FLAGS_DEBUG "${FALCO_EXTRA_DEBUG_FLAGS}")
@@ -72,6 +85,7 @@ if(NOT MSVC)
else() # MSVC
set(MINIMAL_BUILD ON)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
# The WIN32_LEAN_AND_MEAN define avoids possible macro pollution
# when a libsinsp consumer includes the windows.h header.
@@ -82,7 +96,7 @@ else() # MSVC
_CRT_SECURE_NO_WARNINGS
WIN32
MINIMAL_BUILD
WIN32_LEAN_AND_MEAN
WIN32_LEAN_AND_MEAN
)
set(FALCOSECURITY_LIBS_COMMON_FLAGS "/EHsc /W3 /Zi /std:c++17")

View File

@@ -12,22 +12,15 @@
# specific language governing permissions and limitations under the License.
#
#
# cpp-httplib (https://github.com/yhirose/cpp-httplib)
#
if(CPPHTTPLIB_INCLUDE)
# we already have cpp-httplib
option(USE_BUNDLED_CPPHTTPLIB "Enable building of the bundled cpp-httplib" ${USE_BUNDLED_DEPS})
if(USE_BUNDLED_CPPHTTPLIB)
include(FetchContent)
FetchContent_Declare(cpp-httplib
URL https://github.com/yhirose/cpp-httplib/archive/refs/tags/v0.15.3.tar.gz
URL_HASH SHA256=2121bbf38871bb2aafb5f7f2b9b94705366170909f434428352187cb0216124e
)
FetchContent_MakeAvailable(cpp-httplib)
else()
set(CPPHTTPLIB_SRC "${PROJECT_BINARY_DIR}/cpp-httplib-prefix/src/cpp-httplib")
set(CPPHTTPLIB_INCLUDE "${CPPHTTPLIB_SRC}")
message(STATUS "Using bundled cpp-httplib in '${CPPHTTPLIB_SRC}'")
ExternalProject_Add(cpp-httplib
PREFIX "${PROJECT_BINARY_DIR}/cpp-httplib-prefix"
URL "https://github.com/yhirose/cpp-httplib/archive/refs/tags/v0.13.1.tar.gz"
URL_HASH "SHA256=9b837d290b61e3f0c4239da0b23bbf14c382922e2bf2a9bac21c1e3feabe1ff9"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND "")
find_package(httplib CONFIG REQUIRED)
endif()

View File

@@ -12,13 +12,32 @@
# specific language governing permissions and limitations under the License.
#
set(CXXOPTS_SRC "${PROJECT_BINARY_DIR}/cxxopts-prefix/src/cxxopts/")
set(CXXOPTS_INCLUDE_DIR "${CXXOPTS_SRC}/include")
#
# cxxopts (https://github.com/jarro2783/cxxopts)
#
ExternalProject_Add(
option(USE_BUNDLED_CXXOPTS "Enable building of the bundled cxxopts" ${USE_BUNDLED_DEPS})
if(CXXOPTS_INCLUDE_DIR)
# we already have cxxopts
elseif(NOT USE_BUNDLED_CXXOPTS)
find_package(cxxopts CONFIG REQUIRED)
get_target_property(CXXOPTS_INCLUDE_DIR cxxopts::cxxopts INTERFACE_INCLUDE_DIRECTORIES)
else()
set(CXXOPTS_SRC "${PROJECT_BINARY_DIR}/cxxopts-prefix/src/cxxopts/")
set(CXXOPTS_INCLUDE_DIR "${CXXOPTS_SRC}/include")
message(STATUS "Using bundled cxxopts in ${CXXOPTS_SRC}")
ExternalProject_Add(
cxxopts
URL "https://github.com/jarro2783/cxxopts/archive/refs/tags/v3.0.0.tar.gz"
URL_HASH "SHA256=36f41fa2a46b3c1466613b63f3fa73dc24d912bc90d667147f1e43215a8c6d00"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND "")
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND "")
endif()
if(NOT TARGET cxxopts)
add_custom_target(cxxopts)
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 "7cbc03a535ead9d530f7b77ffd68766d5e22da74")
set(DRIVER_CHECKSUM "SHA256=94d110ad1738cce2635fd15d41701bea5e061fd9a5a4be3f2ee8ec7a28fe50cc")
set(DRIVER_VERSION "0.17.0-rc1")
set(DRIVER_CHECKSUM "SHA256=63809beb5e448911f153b8c25f814075238a55f301923aeb3d2374be6309460b")
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.8.0-rc6")
if(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64")
set(FALCOCTL_SYSTEM_PROC_GO "amd64")
set(FALCOCTL_HASH "2d06d7577dbae91fb085f71477ff6e22076a815978bddd036984fa077236a515")
set(FALCOCTL_HASH "af49a15f28281aff37aa57808211cdd0772966a694da3b5a256d0e58e27bd16b")
else() # aarch64
set(FALCOCTL_SYSTEM_PROC_GO "arm64")
set(FALCOCTL_HASH "0b711a1b3499f479d999f4f4d2c94fc4f0bc23a2506711b613e6eedb0593631b")
set(FALCOCTL_HASH "262189f954be20372ff79c5e984b64e530cdfeecc6df74be3b8846fb52ee2bdf")
endif()
ExternalProject_Add(
@@ -35,3 +35,4 @@ ExternalProject_Add(
INSTALL_COMMAND "")
install(PROGRAMS "${PROJECT_BINARY_DIR}/falcoctl-prefix/src/falcoctl/falcoctl" DESTINATION "${FALCO_BIN_DIR}" COMPONENT "${FALCO_COMPONENT_NAME}")
install(DIRECTORY DESTINATION "${FALCO_ABSOLUTE_SHARE_DIR}/plugins" COMPONENT "${FALCO_COMPONENT_NAME}")

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 "7cbc03a535ead9d530f7b77ffd68766d5e22da74")
set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=94d110ad1738cce2635fd15d41701bea5e061fd9a5a4be3f2ee8ec7a28fe50cc")
set(FALCOSECURITY_LIBS_VERSION "0.17.0-rc1")
set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=63809beb5e448911f153b8c25f814075238a55f301923aeb3d2374be6309460b")
endif()
# cd /path/to/build && cmake /path/to/source
@@ -67,12 +67,10 @@ set(SCAP_HOST_ROOT_ENV_VAR_NAME "HOST_ROOT")
set(SCAP_HOSTNAME_ENV_VAR "FALCO_HOSTNAME")
set(SINSP_AGENT_CGROUP_MEM_PATH_ENV_VAR "FALCO_CGROUP_MEM_PATH")
if(NOT LIBSCAP_DIR)
set(LIBSCAP_DIR "${FALCOSECURITY_LIBS_SOURCE_DIR}")
if(NOT LIBS_DIR)
set(LIBS_DIR "${FALCOSECURITY_LIBS_SOURCE_DIR}")
endif()
set(LIBSINSP_DIR "${FALCOSECURITY_LIBS_SOURCE_DIR}")
# configure gVisor support
set(BUILD_LIBSCAP_GVISOR ${BUILD_FALCO_GVISOR} CACHE BOOL "")
@@ -84,12 +82,14 @@ 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_VALIJSON ON CACHE BOOL "")
set(USE_BUNDLED_RE2 ON CACHE BOOL "")
set(USE_BUNDLED_UTHASH ON CACHE BOOL "")
set(USE_BUNDLED_TINYDIR ON CACHE BOOL "")
if(USE_DYNAMIC_LIBELF)
set(USE_BUNDLED_LIBELF OFF CACHE BOOL "")
set(USE_SHARED_LIBELF ON CACHE BOOL "")
endif()
list(APPEND CMAKE_MODULE_PATH "${FALCOSECURITY_LIBS_SOURCE_DIR}/cmake/modules")

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,15 @@
# 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()
option(USE_BUNDLED_NLOHMANN_JSON "Enable building of the bundled nlohmann-json" ${USE_BUNDLED_DEPS})
if(USE_BUNDLED_NLOHMANN_JSON)
include(FetchContent)
FetchContent_Declare(nlohmann_json
URL https://github.com/nlohmann/json/archive/v3.11.3.tar.gz
URL_HASH SHA256=0d8ef5af7f9794e3263480193c491549b2ba6cc74bb018906202ada498a79406
)
FetchContent_MakeAvailable(nlohmann_json)
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
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}'")
find_package(nlohmann_json CONFIG REQUIRED)
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

@@ -1,6 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
#
# Copyright (C) 2023 The Falco Authors.
# Copyright (C) 2024 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
@@ -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")
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

View File

@@ -11,31 +11,16 @@
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
#
mark_as_advanced(YAMLCPP_INCLUDE_DIR YAMLCPP_LIB)
if(NOT USE_BUNDLED_DEPS)
find_path(YAMLCPP_INCLUDE_DIR NAMES yaml-cpp/yaml.h)
find_library(YAMLCPP_LIB NAMES yaml-cpp)
if(YAMLCPP_INCLUDE_DIR AND YAMLCPP_LIB)
message(STATUS "Found yamlcpp: include: ${YAMLCPP_INCLUDE_DIR}, lib: ${YAMLCPP_LIB}")
else()
message(FATAL_ERROR "Couldn't find system yamlcpp")
endif()
add_custom_target(yamlcpp)
option(USE_BUNDLED_YAMLCPP "Enable building of the bundled yamlcpp" ${USE_BUNDLED_DEPS})
if(USE_BUNDLED_YAMLCPP)
include(FetchContent)
FetchContent_Declare(yamlcpp
URL https://github.com/jbeder/yaml-cpp/archive/refs/tags/0.8.0.tar.gz
URL_HASH SHA256=fbe74bbdcee21d656715688706da3c8becfd946d92cd44705cc6098bb23b3a16
)
FetchContent_MakeAvailable(yamlcpp)
else()
set(YAMLCPP_SRC "${PROJECT_BINARY_DIR}/yamlcpp-prefix/src/yamlcpp")
message(STATUS "Using bundled yaml-cpp in '${YAMLCPP_SRC}'")
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.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 "")
find_package(yaml-cpp CONFIG REQUIRED)
endif()

View File

@@ -1,6 +0,0 @@
# Builder folder
* We use `modern-falco-builder.Dockerfile` to build Falco with the modern probe and return it as a Dockerfile output. This Dockerfile doesn't generate a Docker image but returns as output (through the `--output` command):
* Falco `tar.gz`.
* Falco `deb` package.
* Falco `rpm` package.

View File

@@ -1,43 +0,0 @@
FROM centos:7 AS build-stage
# To build Falco you need to pass the cmake option
ARG CMAKE_OPTIONS=""
ARG MAKE_JOBS=6
# Install all the dependencies
WORKDIR /
RUN yum -y install centos-release-scl; \
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++; \
source scl_source enable devtoolset-9; \
yum install -y git wget make m4 rpm-build
# With some previous cmake versions it fails when downloading `zlib` with curl in the libs building phase
RUN curl -L -o /tmp/cmake.tar.gz https://github.com/Kitware/CMake/releases/download/v3.22.5/cmake-3.22.5-linux-$(uname -m).tar.gz; \
gzip -d /tmp/cmake.tar.gz; \
tar -xpf /tmp/cmake.tar --directory=/tmp; \
cp -R /tmp/cmake-3.22.5-linux-$(uname -m)/* /usr; \
rm -rf /tmp/cmake-3.22.5-linux-$(uname -m)/
# Copy Falco folder from the build context
COPY . /source
WORKDIR /build/release
RUN source scl_source enable devtoolset-9; \
cmake ${CMAKE_OPTIONS} /source; \
make falco -j${MAKE_JOBS}
RUN make package
# We need `make all` for integration tests.
RUN make all -j${MAKE_JOBS}
FROM scratch AS export-stage
LABEL org.opencontainers.image.source="https://github.com/falcosecurity/falco"
ARG DEST_BUILD_DIR="/build"
COPY --from=build-stage /build/release/falco-*.tar.gz /packages/
COPY --from=build-stage /build/release/falco-*.deb /packages/
COPY --from=build-stage /build/release/falco-*.rpm /packages/

View File

@@ -37,6 +37,7 @@ RUN apt-get update \
netcat \
patchelf \
xz-utils \
zstd \
&& rm -rf /var/lib/apt/lists/*
RUN if [ "$TARGETARCH" = "amd64" ]; \
@@ -92,7 +93,7 @@ RUN rm -rf /usr/bin/clang \
RUN curl -s https://falco.org/repo/falcosecurity-packages.asc | apt-key add - \
&& echo "deb https://download.falco.org/packages/${VERSION_BUCKET} stable main" | tee -a /etc/apt/sources.list.d/falcosecurity.list \
&& apt-get update -y \
&& if [ "$FALCO_VERSION" = "latest" ]; then apt-get install -y --no-install-recommends falco; else apt-get install -y --no-install-recommends falco=${FALCO_VERSION}; fi \
&& if [ "$FALCO_VERSION" = "latest" ]; then FALCO_DRIVER_CHOICE=none apt-get install -y --no-install-recommends falco; else FALCO_DRIVER_CHOICE=none apt-get install -y --no-install-recommends falco=${FALCO_VERSION}; fi \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

View File

@@ -18,6 +18,32 @@
#
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 " auto leverage automatic driver selection logic (default)"
echo " modern_ebpf modern eBPF CORE probe"
echo " kmod kernel module"
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 " --http-insecure enable insecure downloads"
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 " FALCOCTL_DRIVER_HTTP_HEADERS specify comma separated list of http headers for driver download (e.g. 'x-emc-namespace: default,Proxy-Authenticate: Basic')"
echo ""
}
echo "* Setting up /usr/src links from host"
for i in "$HOST_ROOT/usr/src"/*
@@ -26,4 +52,75 @@ do
ln -s "$i" "/usr/src/$base"
done
/usr/bin/falco-driver-loader "$@"
ENABLE_COMPILE="false"
ENABLE_DOWNLOAD="false"
HTTP_INSECURE="false"
driver=
has_opts=
while test $# -gt 0; do
case "$1" in
auto|kmod|ebpf|modern_ebpf)
if [ -n "$driver" ]; then
>&2 echo "Only one driver per invocation"
print_usage
exit 1
else
driver=$1
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"
;;
--http-insecure)
HTTP_INSECURE="true"
;;
--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
# No opts passed, enable both compile and download
if [ -z "$has_opts" ]; then
ENABLE_COMPILE="true"
ENABLE_DOWNLOAD="true"
fi
# Default value: auto
if [ -z "$driver" ]; then
driver="auto"
fi
if [ "$driver" != "auto" ]; then
/usr/bin/falcoctl driver config --type $driver
else
# Needed because we need to configure Falco to start with correct driver
/usr/bin/falcoctl driver config --type modern_ebpf --type kmod --type ebpf
fi
/usr/bin/falcoctl driver install --compile=$ENABLE_COMPILE --download=$ENABLE_DOWNLOAD --http-insecure=$HTTP_INSECURE --http-headers="$FALCOCTL_DRIVER_HTTP_HEADERS"

View File

@@ -18,6 +18,34 @@
#
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 " auto leverage automatic driver selection logic (default)"
echo " modern_ebpf modern eBPF CORE probe"
echo " kmod kernel module"
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 " --kernel-release <value> set the kernel release"
echo " --kernel-version <value> set the kernel version"
echo " --http-insecure enable insecure downloads"
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 " FALCOCTL_DRIVER_HTTP_HEADERS specify comma separated list of http headers for driver download (e.g. 'x-emc-namespace: default,Proxy-Authenticate: Basic')"
echo ""
}
echo "* Setting up /usr/src links from host"
for i in "$HOST_ROOT/usr/src"/*
@@ -26,4 +54,85 @@ do
ln -s "$i" "/usr/src/$base"
done
/usr/bin/falco-driver-loader "$@"
ENABLE_COMPILE="false"
ENABLE_DOWNLOAD="false"
HTTP_INSECURE="false"
driver=
has_opts=
extra_args=
while test $# -gt 0; do
case "$1" in
auto|kmod|ebpf|modern_ebpf)
if [ -n "$driver" ]; then
>&2 echo "Only one driver per invocation"
print_usage
exit 1
else
driver=$1
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"
;;
--http-insecure)
HTTP_INSECURE="true"
;;
--kernel-release)
extra_args+="--kernelrelease=$2 "
shift
;;
--kernel-version)
extra_args+="--kernelversion=$2 "
shift
;;
--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
# No opts passed, enable both compile and download
if [ -z "$has_opts" ]; then
ENABLE_COMPILE="true"
ENABLE_DOWNLOAD="true"
fi
# Default value: auto
if [ -z "$driver" ]; then
driver="auto"
fi
if [ "$driver" != "auto" ]; then
/usr/bin/falcoctl driver config --type $driver
else
# Needed because we need to configure Falco to start with correct driver
/usr/bin/falcoctl driver config --type modern_ebpf --type kmod --type ebpf
fi
/usr/bin/falcoctl driver install --compile=$ENABLE_COMPILE --download=$ENABLE_DOWNLOAD --http-insecure=$HTTP_INSECURE --http-headers="$FALCOCTL_DRIVER_HTTP_HEADERS" $extra_args

View File

@@ -19,23 +19,33 @@ 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 \
zstd \
&& rm -rf /var/lib/apt/lists/*
RUN curl -s https://falco.org/repo/falcosecurity-packages.asc | apt-key add - \
&& echo "deb https://download.falco.org/packages/${VERSION_BUCKET} stable main" | tee -a /etc/apt/sources.list.d/falcosecurity.list \
&& apt-get update -y \
&& if [ "$FALCO_VERSION" = "latest" ]; then apt-get install -y --no-install-recommends falco; else apt-get install -y --no-install-recommends falco=${FALCO_VERSION}; fi \
&& if [ "$FALCO_VERSION" = "latest" ]; then FALCO_DRIVER_CHOICE=none apt-get install -y --no-install-recommends falco; else FALCO_DRIVER_CHOICE=none apt-get install -y --no-install-recommends falco=${FALCO_VERSION}; fi \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

View File

@@ -17,6 +17,33 @@
# 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 " auto leverage automatic driver selection logic (default)"
echo " modern_ebpf modern eBPF CORE probe"
echo " kmod kernel module"
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 " --http-insecure enable insecure downloads"
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 " FALCOCTL_DRIVER_HTTP_HEADERS specify comma separated list of http headers for driver download (e.g. 'x-emc-namespace: default,Proxy-Authenticate: Basic')"
echo ""
}
# Set the SKIP_DRIVER_LOADER variable to skip loading the driver
if [[ -z "${SKIP_DRIVER_LOADER}" ]]; then
@@ -29,9 +56,81 @@ 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"
HTTP_INSECURE="false"
driver=
has_opts=
for opt in "${falco_driver_loader_option_arr[@]}"
do
case "$opt" in
auto|kmod|ebpf|modern_ebpf)
if [ -n "$driver" ]; then
>&2 echo "Only one driver per invocation"
print_usage
exit 1
else
driver=$opt
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"
;;
--http-insecure)
HTTP_INSECURE="true"
;;
--print-env)
/usr/bin/falcoctl driver printenv
exit 0
;;
--*)
>&2 echo "Unknown option: $opt"
print_usage
exit 1
;;
*)
>&2 echo "Unknown driver: $opt"
print_usage
exit 1
;;
esac
done
# No opts passed, enable both compile and download
if [ -z "$has_opts" ]; then
ENABLE_COMPILE="true"
ENABLE_DOWNLOAD="true"
fi
# Default value: auto
if [ -z "$driver" ]; then
driver="auto"
fi
if [ "$driver" != "auto" ]; then
/usr/bin/falcoctl driver config --type $driver
else
# Needed because we need to configure Falco to start with correct driver
/usr/bin/falcoctl driver config --type modern_ebpf --type kmod --type ebpf
fi
/usr/bin/falcoctl driver install --compile=$ENABLE_COMPILE --download=$ENABLE_DOWNLOAD --http-insecure=$HTTP_INSECURE --http-headers="$FALCOCTL_DRIVER_HTTP_HEADERS"
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
@@ -28,7 +28,7 @@ LABEL org.opencontainers.image.source="https://github.com/falcosecurity/falco"
LABEL usage="docker run -i -t --privileged -v /var/run/docker.sock:/host/var/run/docker.sock -v /dev:/host/dev -v /proc:/host/proc:ro --name NAME IMAGE"
# NOTE: for the "least privileged" use case, please refer to the official documentation
RUN apt-get -y update && apt-get -y install ca-certificates curl jq \
RUN apt-get -y update && apt-get -y install ca-certificates curl jq libelf1 \
&& apt clean -y && rm -rf /var/lib/apt/lists/*
ENV HOST_ROOT /host

View File

@@ -6,7 +6,7 @@ ARG VERSION_BUCKET=bin
ENV FALCO_VERSION=${FALCO_VERSION}
ENV VERSION_BUCKET=${VERSION_BUCKET}
RUN apk update && apk add build-base gcc curl ca-certificates jq
RUN apk update && apk add build-base gcc curl ca-certificates jq elfutils
WORKDIR /
@@ -16,12 +16,12 @@ 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
FROM cgr.dev/chainguard/glibc-dynamic
FROM cgr.dev/chainguard/wolfi-base
LABEL maintainer="cncf-falco-dev@lists.cncf.io"
LABEL org.opencontainers.image.source="https://github.com/falcosecurity/falco"
@@ -29,6 +29,8 @@ LABEL org.opencontainers.image.source="https://github.com/falcosecurity/falco"
LABEL usage="docker run -i -t --privileged -v /var/run/docker.sock:/host/var/run/docker.sock -v /dev:/host/dev -v /proc:/host/proc:ro --name NAME IMAGE"
# NOTE: for the "least privileged" use case, please refer to the official documentation
RUN apk update && apk add libelf libstdc++
ENV HOST_ROOT /host
ENV HOME /root

View File

@@ -25,50 +25,63 @@
#
# (Falco command-line arguments)
# (Falco environment variables)
# Falco config files settings
# config_files [Stable]
# watch_config_files [Stable]
# Falco rules files
# rules_file
# rules_files [Stable]
# Falco rules
# rules [Incubating]
# Falco engine
# engine
# engine [Stable]
# Falco plugins
# load_plugins
# plugins
# Falco config files
# watch_config_files
# load_plugins [Stable]
# plugins [Stable]
# Falco outputs settings
# time_format_iso_8601
# priority
# json_output
# json_include_output_property
# json_include_tags_property
# buffered_outputs
# outputs (throttling)
# rule_matching
# outputs_queue
# time_format_iso_8601 [Stable]
# priority [Stable]
# json_output [Stable]
# json_include_output_property [Stable]
# json_include_tags_property [Stable]
# buffered_outputs [Stable]
# rule_matching [Incubating]
# outputs_queue [Stable]
# Falco outputs channels
# stdout_output
# syslog_output
# file_output
# http_output
# program_output
# grpc_output
# stdout_output [Stable]
# syslog_output [Stable]
# file_output [Stable]
# http_output [Stable]
# program_output [Stable]
# grpc_output [Stable]
# Falco exposed services
# grpc
# webserver
# grpc [Stable]
# webserver [Stable]
# Falco logging / alerting / metrics related to software functioning (basic)
# log_stderr
# log_syslog
# log_level
# libs_logger
# log_stderr [Stable]
# log_syslog [Stable]
# log_level [Stable]
# libs_logger [Stable]
# Falco logging / alerting / metrics related to software functioning (advanced)
# output_timeout
# syscall_event_timeouts
# syscall_event_drops
# metrics
# output_timeout [Stable]
# syscall_event_timeouts [Stable]
# syscall_event_drops [Stable] -> [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 [Stable]
# Falco performance tuning (advanced)
# syscall_buf_size_preset [DEPRECATED]
# syscall_drop_failed_exit [DEPRECATED]
# base_syscalls
# modern_bpf.cpus_for_each_syscall_buffer [DEPRECATED]
# base_syscalls [Stable]
# Falco libs
# falco_libs [Incubating]
########################
# Config maturity tags #
########################
# As per features adoption and deprecation proposal we support 4 levels of configuration keys maturity:
# * Sandbox -> Experimental/alpha features, not recommended for production use, can be removed at any time without further notice.
# * Incubating -> Beta features, long-term support is not guaranteed.
# * Stable -> General Availability (GA) features for which long-term support is expected.
# * Deprecated -> Deprecated keys, soon to be removed.
#
# For more info, please take a look at the proposal: https://github.com/falcosecurity/falco/blob/master/proposals/20231220-features-adoption-and-deprecation.md.
################################
@@ -80,9 +93,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.
@@ -93,27 +106,68 @@
# 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": DEPRECATED. 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
#
# - 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.
###############################
# Falco config files settings #
###############################
# [Stable] `config_files`
#
# Falco will load additional configs files specified here.
# Their loading is assumed to be made *after* main config file has been processed,
# exactly in the order they are specified.
# Therefore, loaded config files *can* override values from main config file.
# Also, nested include is not allowed, ie: included config files won't be able to include other config files.
#
# Like for 'rules_files', specifying a folder will load all the configs files present in it in a lexicographical order.
config_files:
- /etc/falco/config.d
# [Stable] `watch_config_files`
#
# Falco monitors configuration and rules files for changes and automatically
# reloads itself to apply the updated configuration when any modifications are
# detected. This feature is particularly useful when you want to make real-time
# changes to the configuration or rules of Falco without interrupting its
# operation or losing its state. For more information about Falco's state
# engine, please refer to the `base_syscalls` section.
watch_config_files: true
#####################
# Falco rules files #
#####################
# [Stable] `rules_file`
# [Stable] `rules_files`
# NOTICE: Before Falco 0.38, this config key was `rules_file` (singular form), which is now deprecated in favor of `rules_files` (plural form).
#
# Falco rules can be specified using files or directories, which are loaded at
# startup. The name "rules_file" is maintained for backwards compatibility. If
# the entry is a file, it will be read directly. If the entry is a directory,
# startup.
#
# If the entry is a file, it will be read directly. If the entry is a directory,
# all files within that directory will be read in alphabetical order.
#
# The falco_rules.yaml file ships with the Falco package and is overridden with
@@ -142,11 +196,44 @@
# "first match wins" principle. However, enabling the `all` matching option may result
# in a performance penalty. We recommend carefully testing this alternative setting
# before deploying it in production. Read more under the `rule_matching` configuration.
rules_file:
rules_files:
- /etc/falco/falco_rules.yaml
- /etc/falco/falco_rules.local.yaml
- /etc/falco/rules.d
# [Incubating] `rules`
#
# --- [Description]
#
# Falco rules can be enabled or disabled by name (with wildcards *) and/or by tag.
#
# This configuration is applied after all rules files have been loaded, including
# their overrides, and will take precedence over the enabled/disabled configuration
# specified or overridden in the rules files.
#
# The ordering matters and selections are evaluated in order. For instance, if you
# need to only enable a rule you would first disable all of them and then only
# enable what you need, regardless of the enabled status in the files.
#
# --- [Examples]
#
# Only enable two rules:
#
# rules:
# - disable:
# rule: "*"
# - enable:
# rule: Netcat Remote Code Execution in Container
# - enable:
# rule: Delete or rename shell history
#
# Disable all rules with a specific tag:
#
# rules:
# - disable:
# tag: network
#
################
# Falco engine #
################
@@ -164,7 +251,8 @@ rules_file:
# - `modern_ebpf`: Modern eBPF (CO-RE eBPF probe)
# - `gvisor`: gVisor (gVisor sandbox)
# - `replay`: Replay a scap trace file
# - `none`: No event producer loaded, useful to run with plugins.
# - `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,
@@ -312,13 +400,13 @@ rules_file:
# buffers (higher `cpus_for_each_buffer`) can lower the memory footprint.
#
engine:
kind: kmod
kind: modern_ebpf
kmod:
buf_size_preset: 4
drop_failed_exit: false
ebpf:
# path to the elf file to load.
probe: /root/.falco/falco-bpf.o
probe: ${HOME}/.falco/falco-bpf.o
buf_size_preset: 4
drop_failed_exit: false
modern_ebpf:
@@ -393,21 +481,6 @@ plugins:
library_path: libjson.so
######################
# Falco config files #
######################
# [Stable] `watch_config_files`
#
# Falco monitors configuration and rule files for changes and automatically
# reloads itself to apply the updated configuration when any modifications are
# detected. This feature is particularly useful when you want to make real-time
# changes to the configuration or rules of Falco without interrupting its
# operation or losing its state. For more information about Falco's state
# engine, please refer to the `base_syscalls` section.
watch_config_files: true
##########################
# Falco outputs settings #
##########################
@@ -461,7 +534,7 @@ json_include_tags_property: true
# output mechanism. By default, buffering is disabled (false).
buffered_outputs: false
# [Experimental] `rule_matching`
# [Incubating] `rule_matching`
#
# The `rule_matching` configuration key's values are:
# - `first`: Falco stops checking conditions of rules against upcoming event
@@ -482,7 +555,7 @@ buffered_outputs: false
# 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:
@@ -566,6 +639,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`
#
@@ -683,6 +758,11 @@ webserver:
# Can be an IPV4 or IPV6 address, defaults to IPV4
listen_address: 0.0.0.0
k8s_healthz_endpoint: /healthz
# [Incubating] `prometheus_metrics_enabled`
#
# Enable the metrics endpoint providing Prometheus values
# It will only have an effect if metrics.enabled is set to true as well.
prometheus_metrics_enabled: false
ssl_enabled: false
ssl_certificate: /etc/falco/falco.pem
@@ -775,7 +855,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
#
@@ -912,18 +992,29 @@ syscall_event_drops:
# as Falco does not automatically rotate the file. It can be used in combination
# with `output_rule`.
#
# `rules_counters_enabled`: Emit counts for each rule.
#
# `resource_utilization_enabled`: Emit CPU and memory usage metrics. CPU usage
# is reported as a percentage of one CPU and can be normalized to the total
# 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
@@ -946,16 +1037,22 @@ syscall_event_drops:
# beneficial for exploring the data schema and ensuring that fields with empty
# values are included in the output.
#
# todo: prometheus export option
# If metrics are enabled, the web server can be configured to activate the
# corresponding Prometheus endpoint using `webserver.prometheus_metrics_enabled`.
# Prometheus output can be used in combination with the other output options.
#
# todo: syscall_counters_enabled option
metrics:
enabled: false
interval: 1h
# Typically, in production, you only use `output_rule` or `output_file`, but not both.
# However, if you have a very unique use case, you can use both together.
# Set `webserver.prometheus_metrics_enabled` for Prometheus output.
output_rule: true
# output_file: /tmp/falco_stats.jsonl
rules_counters_enabled: true
resource_utilization_enabled: true
state_counters_enabled: true
kernel_event_counters_enabled: true
libbpf_stats_enabled: true
convert_memory_to_mb: true
@@ -965,76 +1062,6 @@ metrics:
# Falco performance tuning (advanced) #
#######################################
# [DEPRECATED] `syscall_buf_size_preset`
#
# 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]
#
# 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.
syscall_buf_size_preset: 4
# [DEPRECATED] `syscall_drop_failed_exit`
#
# 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 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.
syscall_drop_failed_exit: false
# [Stable] `base_syscalls`, use with caution, read carefully
#
# --- [Description]
@@ -1150,89 +1177,28 @@ base_syscalls:
custom_set: []
repair: false
# [DEPRECATED] `modern_bpf.cpus_for_each_syscall_buffer`, modern_bpf only
##############
# Falco libs #
##############
# [Incubating] `falco_libs`
#
# 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.
# `thread_table_size`
#
# --- [Description]
# Set the maximum number of entries (the absolute maximum value can only be MAX UINT32)
# for Falco's internal threadtable (process cache). Please note that Falco operates at a
# granular level, focusing on individual threads. Falco rules reference the thread leader
# as the process. The size of the threadtable should typically be much higher than the
# number of currently alive processes. The default value should work well on modern
# infrastructures and be sufficient to absorb bursts.
#
# 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
# `syscall_buf_size_preset` index. For instance, you can create a large shared
# syscall buffer of 512 MB (using syscall_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 syscall_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_syscall_buffer`) can lower the memory footprint.
modern_bpf:
cpus_for_each_syscall_buffer: 2
# Reducing its size can help in better memory management, but as a consequence, your
# process tree may be more frequently disrupted due to missing threads. You can explore
# `metrics.state_counters_enabled` to measure how the internal state handling is performing,
# and the fields called `n_drops_full_threadtable` or `n_store_evts_drops` will inform you
# if you should increase this value for optimal performance.
falco_libs:
thread_table_size: 262144
# [Stable] Guidance for Kubernetes container engine command-line args settings
#

View File

@@ -0,0 +1,112 @@
# On Host Anomaly Detection Framework - New `anomalydetection` Plugin
## Motivation
**A Wind of Change for Threat Detection**
Feel that light breeze? That is the continued advancement of cloud native security blowing steady. But despite our progress, threat actors are outpacing our innovation constantly finding new ways to thwart and tornado past our achievements — rule-based detections focus on what we *think* attackers will do, not on what they *are* doing and generate enough alerts to bury security analysts in a sandstorm of poor signal-to-noise. Can this dynamic be blown back to shift the information asymmetry in favor of defenders?
This framework lays the foundation on how to create high-value, kernel signals that are difficult to bypass - but not in the traditional way. Advanced data analytics is an emerging crosswind that enables us to soar past attackers by detecting deviations in current behavior from past behavior.
## Benefits to the Ecosystem
Advanced data analytics enables us to combine the intricacies of the Linux kernel with on-host anomaly detection in cloud native and cloud environments to determine patterns of past behavior in running applications. By detecting deviations in current behavior from past behavior, we can shift the focus away from relying solely on signatures and rule matching to catch attackers.
Threat detection in open source and more importantly cloud native is constrained by the amount of rules we can write and the signatures we know to look for in our environments. But these have the same problem: they assume our attackers don't change what they're doing. The reality is attackers are not limited to the ways, means, and methods they employ to expose, manipulate, or even destroy our data, systems, and organizations.
This framework leverages an attacker's mindset applied to detection engineering: observing and learning about our targets to create more rich and actionable alerts so we can catch them earlier and more often - regardless if it's behavior we know about, or something we haven't seen yet.
## Elevator Pitch
When Falco processes events in userspace, its rules engine filters the events while the parsers simultaneously update and maintain an internal state. This state includes a process tree cache that enhances Falco alerts by providing contextual information derived from previous events. The goal is to enhance the "state engine" even further and provide an option for monitoring the behavior of applications over time.
To achieve this, end users define a "behavior profile" in the configuration by combining existing event fields such as process name, file descriptor (fd), executable path, parent lineage, cmdline, and others. During event parsing on the hot path, Falco compresses and stores this information in a "filter" - an efficient probabilistic data structure that optimizes space, time, robustness and accuracy. As time progresses, Falco provides more accurate estimates of application behavior counts and identifies events as rare or heavy hitters. Instead of analyzing the original event stream, you can write Falco rules based on pre-filtered data.
This approach introduces a novel threat detection framework that analyzes abnormal application behavior in real-time, derived and observed in a data-driven fashion, without requiring operator reconfiguration of Falco. It complements the operator's expertise and extends capabilities similar to our current practices. The new capability draws inspiration from big data stream and database query optimizations, ensuring that Falco maintains a streamlined real-time one-pass stream with zero allocations.
Similar to Falco rules, the analysis of events may require multiple behavior profiles of different dimensions based on sets of events. These profiles can either vote in parallel or in a cascading fashion, a common practice in established algorithms. This is just the beginning and and paves the way for more sophisticated approaches, such as running Falco in a DAST-like capacity to build a pre-state pattern file on a workload with test data and soften the cold-start via distributing it to production.
## Challenges and Considerations
First, The Falco Project is committed to continuously ensuring access to the most accurate data possible for on-host threat detection. As an example, recent efforts involved expanding kernel signal logging, such as verifying if an execve call is linked to a file descriptor existing exclusively in memory or improving the efficient and reliable resolution of symlinks for executable paths. Therefore, the proposed anomaly detection framework operates under the assumption of having the *correct* data, thereby complementing the ongoing efforts to expand logging coverage and improve its quality. In summary, the primary focus of the framework is to derive increased value from the existing *right* data that is currently available.
There is a common perception that attacks on running cloud applications, as well as their indicators of compromise, are typically rare when the appropriate data or combination of signals is considered. While this holds true, there are inherent challenges in applying this concept of rarity to robust data analytics approaches.
On the one hand, this is due to the diverse range of attacks and attack vectors. An attacker may introduce a new malicious binary (which is comparatively easier to detect using traditional rules and high-value kernel signals) after gaining initial access. Alternatively, they may exploit existing binaries, shell built-ins, and employ obfuscation techniques to "live off the land". The Turing completeness of the latter scenario, in particular, leads to an infinite number of attack possibilities.
However, what poses even more challenges in anomaly detection lies not necessarily in the nature of attacks but rather in identifying the right signals and their appropriate combinations for robust analytics to distinguish between normal and anomalous behavior. This challenge becomes particularly evident when considering the natural fluctuations in application behavior over time and the occurrence of ad-hoc legitimate debugging activities. Such fluctuations can arise from various factors, including routine deployment updates. Moreover, certain applications may produce random file names or execute arbitrary executable paths as part of their regular operations, adding to the challenge of anomaly detection. This is compounded by the inherent "cold start" issue when initially observing an application. In such cases, the algorithms must demonstrate flexibility and robustness by recognizing and encoding consistent patterns, similar to how humans can identify the sameness by examining combinations of file names, command arguments, parent process lineage, and other attributes. Furthermore, factors like data inconsistency and the diverse forms of data representations (comprising a mix of numeric data and strings with varying meanings) further complicate the task.
We believe it is important to incorporate operator heuristics or domain knowledge into the algorithm's definition of rarity. For example, while current algorithms are capable of generating human faces, they used to frequently produce images with different eye colors. However, if we were to inform the machine that humans typically have matching eye colors, it could easily correct this discrepancy. This highlights the role of the security engineer as a guiding hand to the algorithms, both in terms of handling noise tolerance and choosing the appropriate data to be ingested into the algorithm. This is crucial as machines are currently limited in their ability to draw meaningful observations from limited data and constrained memory. In summary, this is where the fusion of data-driven anomaly detection and rules matching will come into play.
Lastly, the value proposition of conducting real-time anomaly analysis on the host lies in the unique options it offers, which cannot be achieved through alternative methods. On the host, we can observe anomalies based on all relevant and observed kernel events. In contrast, sending a large volume of kernel events to a centralized system would be impractical, resulting in significant costs for data pipeline management and data lake compute expenses.
## Initial Scope
The initial scope is to implement the Count Min Sketch algorithm using n shared sketches and expose its count estimates as new filterchecks for use in Falco rules. An MVP can be explored in this libs draft PR [wip: new(userspace/libsinsp): MVP CountMinSketch Powered Probabilistic Counting and Filtering](https://github.com/falcosecurity/libs/pull/1453). Moreover, the initial anomaly detection framework will include a transparent `plugin` user interface for defining application behavior profiles and utilizing sketch count estimates in Falco rules. The primary direct benefit lies in establishing a safety boundary for Falco rules in production environments, allowing for broader rule monitoring while preventing Falco rules from blowing up in production.
Furthermore, The Falco Project will provide adopters with valuable initial use cases, recommended thresholds, and callouts for known issues. One important consideration is the identification of SRE anti-patterns. Another consideration is to provide *very clear* guidance to adopters for setting and configuring parameters, including recommended minimums. Additionally, guidance should be provided on indicators to look for in order to determine if adjustments need to be made and in which direction, particularly when defining application behavior profiles.
## High-Level Technical Design of a New `anomalydetection` Plugin
This document provides a high-level proposal with limited technical details.
*Probabilistic Data Structures*
One option for implementing the probabilistic filter is by utilizing a robust two-dimensional probabilistic data structure known as the Count Min Sketch. This data structure is widely employed in distributed stream processing frameworks such as Apache Spark, Apache Storm, Apache Flink, and others, as well as databases like Redis and PostgreSQL.
Technical details and implications are extensively covered in numerous research papers and textbooks. Therefore, here are some key points to consider in order to make informed choices:
- The challenges posed by both hard and soft collisions can be mitigated by using multiple non-cryptographic hash functions, which has been mathematically proven to be effective.
- Despite providing one-sided error bounds and preventing undercounting, the sketchy data structure requires adopters to define a tolerance level for overcounting. This tolerance level determines what qualifies as rare or noteworthy.
- To enhance accuracy and reduce estimation errors, consider debiasing data (e.g. Count Min Sketch with Conservative Updates) or applying a logarithmic scale to address kernel event data skew. The logarithmic scale may suit threat detection, targeting low-frequency or long-tail attack-related items. However, only use if performance overhead is acceptable.
- Use larger shared sketches and incorporate container IDs as part of the behavior profiles to differentiate between workloads / applications. Conversely, use separate sketches for distinct behavior profiles, also known as the "what we are counting".
- ... and numerous other aspects that will be discussed in subsequent implementation PRs.
*Plumbing and Interface*
The ultimate goal is to introduce these new capabilities as plugin. A significant amount of work will be dedicated to addressing the necessary plumbing required to support the new framework and integrate it with the existing rules filtering, `libsinsp` and `plugin` mechanisms. This integration aims to provide a user-friendly interface that allows users to easily configure and utilize the opt-in framework for different use cases.
For instance, the interface should empower end users to define error tolerances and, consequently, sketch dimensions, along with other tuning parameters, bounds, and settings. Ultimately, it should enable the definition of n behavior profiles to facilitate the use of count estimates in Falco rules.
## What this Framework is Not
- This framework is not intended to function as an event aggregator or enhancer, such as netflow data. Its sole purpose is to serve as an anomaly filter for individual events, utilizing the existing sinsp state, the newly built state through sketches, and the current rules engine.
- The development of this framework will not be swayed by overly specific use cases that limit its broader adoption and coverage.
- While it may not offer flawless attack threat detection from the beginning, it serves as an initial step towards comprehensive event logging and analysis, capturing all events that exhibit any form of new or changing behavior we observe. Therefore, initially, the greatest value lies in combining it with regular Falco rules based on the anomaly-filtered event stream.
## Why now?
In case you haven't noticed, advanced data analytics is quite the big deal these days, and we can leverage robust established algorithms used in real production settings across various industries. The novelty lies in addressing the specific data encoding challenges unique to the field of cybersecurity, not re-inventing already established algorithms.
Furthermore, over the past several Falco releases, we have significantly improved stability, configurability, and capabilities. Notably, the plugins system has been refined over the past year to efficiently access the complete `libsinsp` state, now also featuring an improved CPP SDK. Additionally, it now seamlessly collaborates with the existing primary syscalls event source, deviating from its original purpose of processing new data sources. This improvement allows for more intuitive functionality, as demonstrated by the new `k8smeta` plugin. Now is the opportune time to further enhance proven threat detection capabilities and expand the plugins system even more.
*Initial community feedback concerning the KubeCon NA 2023 Full Talk*
- Overall, the feedback for [A Wind of Change for Threat Detection](https://kccncna2023.sched.com/event/1R2mX/a-wind-of-change-for-threat-detection-melissa-kilby-apple) was very positive and appreciative, particularly regarding the direct real-life benefits (a safety boundary for Falco rules enabling broader monitoring that won't blow up in production). Suggestions for future development included integrating the sketch directly into the kernel driver (which would be a remarkable achievement if feasible). Lastly, people have inquired about the timeline for the availability of this feature.
- Refer to the [KubeCon NA 2023 Slides](https://static.sched.com/hosted_files/kccncna2023/c5/A%20Wind%20of%20Change%20for%20Threat%20Detection%20-%20Melissa%20Kilby%20-%20KubeCon%20NA%202023.pdf) or [attached PDF](kubeconna23-anomaly-detection-slides.pdf) for more information. Here's the [Talk Recording](https://www.youtube.com/watch?v=1y1m9Vz93Yo) (please note that the first four minutes of the video are missing, but the slides and audio recordings are complete).
*Falco Community Call - January 17, 2024*
See dedicated [HackMD](https://hackmd.io/Ss0_1avySUuxArBQm-oaGQ?view):
- While not blocking the start of the plugin or an alpha dev version, there's feedback from @jasondellaluce that plugins cannot access the existing `libsinsp` filtercheck. It would be advantageous to enable this access to avoid reimplementing them and the constant risk of falling out of sync with `libs`. @leogr mentioned that supporting this over time should be possible.
- We have discussed the plugins config and are currently undecided on whether the definition of the behavior profile per sketch, meaning the fields that are string concatenated together and counted, should reside in the plugins config or in the rules files. The latter would potentially require a new rules component. Final decisions will be deferred to a later stage to ensure the config is intuitive, and we want to guarantee proper sketch definition when attempting to run Falco rules using the `anomalydetection` plugin.
- One use case, namely determining if a rule has previously occurred in a container, could be addressed by this framework as well. However, we are currently unsure how to expose the rule names, as `libsinsp` is not aware of them. This may be an optimization we can address later and does not block the development of an initial version.
- Future use cases might involve counting distinct values, utilizing the hyper log log algorithm. However, there will be additional technical challenges to overcome.
- Finally, just to reiterate some feedback from the KubeCon talk, there's a suggestion that, perhaps in the future, we could pass intelligence back and forth between the drivers and userspace. This idea has been discussed independently, especially in the context of kernel-side filtering. However, such capabilities would be a long-term consideration.
## Proposed Timelines
- Falco 0.37.0: Design details and scaffolding
- Falco 0.38.0: Experimental release
- Falco 0.39.0: First release
## Resources / References
- [Probabilistic Data Structures and Algorithms
for Big Data Applications](https://www.gakhov.com/books/pdsa.html) book
- [Count Min Sketch blog 1](https://towardsdatascience.com/big-data-with-sketchy-structures-part-1-the-count-min-sketch-b73fb3a33e2a)
- [Count Min Sketch blog 2](https://www.synnada.ai/blog/probabilistic-data-structures-in-streaming-count-min-sketch)
- [Count Min Log Sketch](https://arxiv.org/pdf/1502.04885.pdf) paper
- [Count Min Sketch with Conservative Updates](https://hal.science/hal-03613957/document#:~:text=Count%2DMin%20Sketch%20with%20Conservative%20Updates%20(CMS%2DCU),because%20of%20its%20inherent%20difficulty) paper
- [xxHash](https://github.com/Cyan4973/xxHash) as new dependency for fast and reliable hashing (using xxh3)

View File

@@ -0,0 +1,219 @@
# Features Adoption and Deprecation Policies Proposal
This proposal aims to introduce a balance between maintaining adopter trust and the need for The Falco Project to evolve. Historically, Falco has favored rapid evolution over providing long-term support for features and interfaces. However, some project subsystems have been implicitly assumed not to allow backward-incompatible changes (e.g., we have almost never removed a condition syntax field). These implicit conventions have never been formalized, and decisions in this regard have been left unspecified.
## Goals
- Establish adopter expectations on the operational cost of using Falco.
- Provide a clear path for features to be adopted and dismissed.
- Allow quick evolution and experimentation without disrupting our adopters' deployments.
- Detail the process for introducing new features, following a "sandbox" to "incubating" to "stable" progression.
- Define the scope of the policy, including which aspects of Falco are covered (e.g., command line flags, configuration files, rules syntax).
- Establish stages for deprecating features, aligning with the project's current status (pre- and post-1.0 stages).
- Adopt a semantic versioning (semver) approach.
## Non-Goals
- Define the number of previous releases that will receive patches or security updates and the duration of this support.
- Define the criteria for Falco 1.0.
## Scope
The proposed policies apply to Falco, its subsystems (e.g., rules, the plugin system), and all [core projects](https://github.com/falcosecurity/evolution#core) which are deemed [stable](https://github.com/falcosecurity/evolution/blob/main/REPOSITORIES.md#stable), thus officially supported by The Falco Project.
## Definitions
### Feature Changes
A feature is a distinct and specific functionality or characteristic of Falco and its core components that provides value to the user by enabling them to perform particular tasks. Features encompass aspects such as functionality, user value, usability, integrability, scalability, configurability, and discoverability. Features can range from essential user interface elements to complex, multifunctional operations.
A feature change refers to any modification or update to an existing feature or the addition of a new feature. This does not include documentation, Falco compatibility across different environments, platforms, systems, or other software or hardware, bug fixing (stated it does not require a feature change to overcome the problem), and performance (unless a change produces a measurable effect on usability).
### Behavior Changes
A behavior change refers to alterations in how Falco, or a specific feature within it, operates or responds under certain conditions. Unlike feature changes, behavior changes are more about tweaking the underlying logic or the way existing features interact or perform, particularly the expected behavior of Falco when run with the default configuration.
Behaviors are generally documented. Any modification that does not meet the conditions and expectations of an already documented feature is assumed to be a behavior change.
Undocumented behaviors may be included in this definition if there's strong evidence or suspicion that users rely on those undocumented behaviors.
### User-Facing Changes
User-facing changes refer to any feature changes, behavior changes, modifications, or additions that are directly noticeable and interactable by the end users. These changes affect how Falco operates from the user's perspective (notably any change that can lead to user disruption). Unlike internal changes (i.e., code refactoring, CI, maintenance-related changes), which are under-the-hood improvements not directly visible to the user, user-facing changes are evident in the Falco and its core components interface and functionality.
### CLI/Config Area
Falco is comprised of the Falco binary and other programs and tools cooperating (notably [falcoctl](https://github.com/falcosecurity/falcoctl)). These programs are the primary user interface for Falco. Any feature or behavior changes to the following elements of these programs are assumed to be user-facing changes to the CLI/Config area:
- Program name.
- Distribution mechanism and packaging (e.g., a container image).
- Command line flags and options.
- Environment variables.
- Configurations.
- Elements that affect the program's lifecycle (e.g., the effect of sending a SIGINT to the program).
- Elements that allow scripting, automation, or interaction with other programs (e.g., piping and redirection).
- Program inputs, excluding elements explicitly governed by other areas (e.g., [Falco rules](#rules-area)).
- Program outputs excluding elements explicitly governed by other areas (e.g., [Falco outputs/alerts](#outputs-alerts-area)).
### Rules System Area
Rules are the primary input for Falco. Any feature or behavior changes to the following aspects or elements are assumed to be user-facing changes to the rules system area:
- Syntax.
- File format.
- Schema (i.e., supported fields).
- Elements that affect the way users can implement rules.
- Elements that affect the way rules are triggered.
However, any change related to the rule's output when triggered (i.e., the alert) is out of scope for this area (see next section).
Note that this area does not include changes related to the ruleset files. Ruleset distributions follow their own [Rules Maturity Framework](https://github.com/falcosecurity/rules/blob/main/CONTRIBUTING.md#rules-maturity-framework) policies.
### Outputs/Alerts Area
Alerts, delivered through Falco output channels, are Falco's primary output. The way and the format in which alerts are produced can have a significant impact on adopters. For example, removing a supported rule field also impacts this area, as adopters may have relied on that field when consuming Falco output.
Any feature or behavior changes to the following aspects or elements are assumed to be user-facing changes to the Outputs/Alerts area:
- Output and logging formats.
- Schema of outputted data (i.e., supported fields).
- Falco output channels.
- Any element that might be consumed from the output.
### Subsystem APIs (Plugins, gRPC Output, Metrics, etc.) Area
Falco is also comprised of several subsystems providing specific APIs. These subsystems notably include plugin system API, gRPC output API, and metrics API.
In the context of this proposal, only changes to **public APIs** are assumed to be user-facing changes to this area.
Public APIs are defined as those supporting Falco functioning and explicitly intended for user usage. Internal APIs consumed by Falco or other tools are out of scope for this area. For instance, the driver APIs or libs APIs are intended to be mainly consumed by Falco and not by users.
### Platform Support Area
Platform support for Falco encompasses the range of platforms, systems, and environments it is designed to operate in. Platform support may significantly vary by Falco's data sources and use cases. For example, its compatibility differs when utilized for Kubernetes audit events versus system call events. Additionally, platform support can be influenced by deployment methods (e.g., directly on a host versus within Kubernetes) or configurations (e.g., running in privileged versus least privileged mode).
Given the diversity of potential platforms and setups, only those explicitly listed in Falco's documentation are considered officially supported. While Falco may function on other platforms, official support is guaranteed solely for documented ones.
Therefore, changes in platform compatibility or behavior that are documented explicitly assumed to be user-facing changes to the Platform Support area.
### Release Cycle
In the context of this proposal, a release cycle is the period between two consecutive major or minor releases of Falco. Hotfix/Patch releases must not be counted.
The actual duration of a release cycle can vary. Still, it's assumed to be about 16 weeks (as per our current defined [Release Cycles and Development Iterations](https://github.com/falcosecurity/falco/blob/master/proposals/20230511-roadmap-management.md#release-cycles-and-development-iterations)). In case of future modification to the Falco release schedule, a period of minimum 3 months must be assumed.
## Proposal
### Maturation Levels
Maturation levels (inspired by those we already have in place for [repositories](https://github.com/falcosecurity/evolution/blob/main/REPOSITORIES.md#status)) are used to characterize the maturity of a feature. Each feature will have an assigned level at any specific time (i.e., a Falco release). Levels are shown in the table below.
| Maturity Level | Intended for |
| --- | --- |
| Sandbox | Experimental/alpha features, not recommended for production use, can be removed at any time without further notice. |
| Incubating | Beta features, long-term support is not guaranteed. |
| Stable | General Availability (GA) features for which long-term support is expected. |
| Deprecated | See the [deprecation policy](#Deprecation-policy) section below. |
### Adoption Policy
The adoption policy applies to any backward compatible user-facing changes which add functionalities. For non-backward compatible changes see the [deprecation policy](#Deprecation-policy) below.
**Adoption rules**:
1. A feature can be introduced at only one of the following levels:
- Sandbox: The feature must be opt-in (e.g., not enabled by default), labeled as *Sandbox* and the user must be proactively informed by the experimental nature of the feature (i.e. emitting a notice when the feature is being enabled).
- Incubating: The feature must be labeled as *Incubating*.
2. Any functionality additions to an existing feature are inherently introduced at the same level as the feature itself unless logically separable (for instance, a sub-feature that may be enabled separately).
3. A feature can be promoted *from Sandbox to Incubating* or *from Incubating to Stable* only after at least one release cycle has passed without user-facing changes to the feature.
4. A feature cannot be demoted to a previous level.
_Note about behaviors_:
This policy indirectly applies to behaviors, too. Behavior changes are assumed to be a consequence of a feature change. The adoption level of a documented behavior is considered to be the same as the related feature. Furthermore, behavior changes are particularly relevant in the context of deprecation (see the next section).
### Deprecation Policy
The deprecation policy applies to any non-backward compatible user-facing changes. Any other changes introduced in a backward-compatible manner does not fall under the scope of this deprecation policy.
**Deprecation rules**:
1. Sandbox features can be removed or changed at any time without notice. No deprecation period is required.
2. Incubating or Stable features and documented behaviors must enter a deprecation period and function for no less than the indicated release cycles (see tables below) after their announced deprecation.
- If the change affects the feature partially, the deprecation applies only to that feature part.
- If the change removes the feature entirely, the deprecation applies to the entire feature.
3. At least for the entire deprecation period, the feature must be labeled as *Deprecated* in all relevant documentation, and:
- for deprecated configurations or CLI elements, a warning must be emitted warnings when the feature is being enabled or used;
- for deprecated APIs, when technically feasible, the API should be signal the deprecation status (this may vary depending on the specific subsystem);
- for deprecated behaviors the documentation must highlight the _before_ and _after_ behavior, alongside with a prominent deprecation notice.
4. Any Pull Request introducing a deprecation notice must be labeled and include a note in the format `DEPRECATION NOTICE: ...`.
5. Any Pull Request introducing a breaking change due to the end of the deprecation notice period must be labeled and include a note in the format `BREAKING CHANGE: ...`.
- It is also recommended for code commits that introduce a breaking change to follow the related [conventional commit spec](https://www.conventionalcommits.org/en/v1.0.0/#specification).
The minimum deprecation period length depends on the affected area. If a single change spans multiple areas, the area with the most extended deprecation period is assumed. Longer deprecation periods are allowed if the feature is deemed to be particularly critical or widely used.
#### Deprecation Period Lengths
_The units represent the number of releases._
##### Before Falco 1.0
| Area | Stable | Incubating |
| -------------- | ------ | ---------- |
| *all areas* | 1 | 0 |
##### Since Falco 1.0 onward
| Area | Stable | Incubating |
| -------------- | ------ | ---------- |
| Behaviors | 2 | 1 |
| Rules System | 2 | 1 |
| Output/Alerts | 2 | 1 |
| Platform | 2 | 1 |
| CLI/Config | 1 | 1 |
| Subsystem APIs | 1 | 0 |
### Examples
**Example 1** Let's consider a feature _foo_ in the Output/Alerts Area introduced in Falco 1.0.0 and labeled as *Incubating*. The feature is promoted to *Stable* in Falco 1.1.0 (because the feature did not get any user-facing change).
Subsequently, maintainers decide that backward-compatible changes must be introduced in _foo_ to improve its functionality. The part of the feature to be changed is labeled as *Deprecated* in Falco 1.2.0, and the deprecation period starts. The non-backward compatible change is then introduced in Falco 1.4.0.
**Example 2** The `--bar` flag in the CLI/Config Area has been introduced since Falco 1.1.0 and is labeled as *Stable*. Before releasing Falco 1.5.0, maintainers realize `--bar` is redundant and should be removed. The flag is labeled as *Deprecated* in Falco 1.5.0, and the deprecation period starts. The flag is removed in Falco 1.6.0.
### Exceptions
- Ruleset in the official distributions follow the [Rules Maturity Framework](https://github.com/falcosecurity/rules/blob/main/CONTRIBUTING.md#rules-maturity-framework) policies.
- Subsystems or subcomponents may have additional criteria and exceptions. Stated other criteria and exceptions must not directly affect the main Falco distribution (e.g., *falcoctl* can have a different release cycle and different policies; however, if Falco relies on a specific *falcoctl* feature, that *falcoctl* feature adoption and deprecation must be strictly compatible with the rules described in this proposal).
- Internal APIs are out of scope for this policy. Their adoption models and deprecation policies might be regulated separately.
- Different parties may provide plugins, and each plugin may have a different maturity level. Only those plugins officially maintained by The Falco Project and identified as "core" for Falco are in scope for this policy; all others are excluded.
- Any other exceptions to the rules provided by this policy require a formal core maintainer majority vote.
### Versioning
Regarding the above policies, component versioning must adhere to [Semantic Versioning 2.0.0](https://semver.org/). However, in the context of Falco core components, the scope extends beyond the strict API definition and includes any user-facing changes.
Thus, given a version number `MAJOR.MINOR.PATCH` increment the:
- *MAJOR* version when the deprecation period of one or more _stable_ features ends, thus introducing incompatible user-facing or API changes.
- *MINOR* version when adding functionality in a backward-compatible manner.
- *PATCH* version when making backward-compatible bug fixes.
Moreover, *MAJOR* version zero (0.y.z) is for versioning stabilization (i.e., before defining the public set of user-facing features and APIs). At this stage, the *MINOR* version is allowed to be incremented instead of the *MAJOR* version.
### Documentation
Documentation must be tied to a specific release and reflect the adoption level status of a feature at that specific release. In particular:
- Deprecated items must be labeled `DEPRECATED` in all relevant documentation.
- Stable items must be sufficiently documented. Explicitly labeling the Stable status is not required or recommended.
- Incubating items must be sufficiently documented and labeled `INCUBATING` in all relevant documentation.
- Sandbox items may be partially documented and labeled `SANDBOX` in all relevant documentation, if any. The relevant documentation must also explicitly state the experimental nature of the item.
## Transition Phases
Since software components may need to adapt to implement the requirements this proposal mandates, we assume the following stages are required to transition from the current state to the desired state fully:
- Within Falco 0.38, at least stable features must be identified, and the adoption policy and relevant documentation should be implemented in Falco. Exceptions may be made temporarily for the deprecation policy.
- Within subsequent releases and no later than Falco 1.0.0 (still not scheduled to date), all the policies must be strictly implemented in Falco and documented in [falco.org](falco.org). The [Rules Maturity Framework](https://github.com/falcosecurity/rules/blob/main/CONTRIBUTING.md#rules-maturity-framework) must be adapted to ensure it aligns with the spirit of this proposal. Exceptions may be made temporarily for other [core projects](https://github.com/falcosecurity/evolution#core) with [stable](https://github.com/falcosecurity/evolution/blob/main/REPOSITORIES.md#stable) status, assuming exceptions don't severely affect the main Falco distribution.
- Within Falco 1.1.0, all the policies must be strictly implemented in Falco and in all [core projects](https://github.com/falcosecurity/evolution#core) with [stable](https://github.com/falcosecurity/evolution/blob/main/REPOSITORIES.md#stable) status.
During the transition phases, maintainers can fine-tune these policies and add further exceptions, eventually. After this initial transition phases, the policy is assumed to be established. From then on, any policy modifications, updates, and exceptions must be subject to a core maintainer majority vote to ensure the policy remains relevant and practical.

Binary file not shown.

View File

@@ -41,17 +41,24 @@ 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
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()
set(FALCOCTL_DRIVER_TYPES_LIST "")
if (BUILD_FALCO_MODERN_BPF)
list(APPEND FALCOCTL_DRIVER_TYPES_LIST "modern_ebpf")
endif()
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/falcoctl/falcoctl.yaml DESTINATION "${FALCOCTL_ETC_DIR}" COMPONENT "${FALCO_COMPONENT_NAME}")
if (BUILD_DRIVER)
list(APPEND FALCOCTL_DRIVER_TYPES_LIST "kmod")
endif()
if (BUILD_BPF)
list(APPEND FALCOCTL_DRIVER_TYPES_LIST "ebpf")
endif()
string(REPLACE ";" ", " FALCOCTL_DRIVER_TYPES "${FALCOCTL_DRIVER_TYPES_LIST}")
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

@@ -17,7 +17,10 @@
# limitations under the License.
#
chosen_driver=
# By default, we use the automatic selection for drivers
chosen_driver="auto"
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 +39,76 @@ 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" \
# "auto" case is not managed here since it is already the default, so no CHOICE=2
case $FALCO_DRIVER_CHOICE in
none)
CHOICE=1
;;
kmod)
CHOICE=3
;;
ebpf)
CHOICE=4
;;
modern_ebpf)
CHOICE=5
;;
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 "Automatic selection" \
3 "Kmod" \
4 "eBPF" \
5 "Modern eBPF" \
2>&1 >/dev/tty)
fi
# "auto" case is not managed here since it is already the default, so no CHOICE=2
case $CHOICE in
1)
chosen_driver=""
;;
3)
chosen_driver="kmod"
;;
4)
chosen_driver="ebpf"
;;
5)
chosen_driver="modern_ebpf"
;;
esac
if [ -n "$chosen_driver" ]; then
echo "[POST-INSTALL] Configure falcoctl '$chosen_driver' driver type:"
if [ "$chosen_driver" = "auto" ]; then
# Configure falcoctl to enable all drivers
falcoctl driver config --type "modern_ebpf" --type "kmod" --type "ebpf"
# Load the actually automatic chosen driver
chosen_driver=$(falcoctl driver printenv | grep DRIVER= | cut -d'"' -f2)
else
falcoctl driver config --type "$chosen_driver"
fi
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 +116,30 @@ 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
chosen_unit="kmod"
;;
"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
chosen_unit="bpf"
;;
"modern_ebpf")
chosen_unit="modern-bpf"
;;
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,9 +1,16 @@
driver:
type: [@FALCOCTL_DRIVER_TYPES@]
name: "@DRIVER_NAME@"
repos:
- "@DRIVERS_REPO@"
version: "@DRIVER_VERSION@"
hostroot: "/"
artifact:
follow:
every: 6h0m0s
falcoVersions: http://localhost:8765/versions
refs:
- falco-rules:0
- falco-rules:3
indexes:
- name: falcosecurity
url: https://falcosecurity.github.io/falcoctl/index.yaml

View File

@@ -39,9 +39,15 @@ fi
s3_bucket_repo="s3://falco-distribution/packages/${repo}/${arch}"
cloudfront_path="/packages/${repo}/${arch}"
# sign
gpg --detach-sign --digest-algo SHA256 --armor ${file}
# publish
package=$(basename -- ${file})
echo "Publishing ${package} to ${s3_bucket_repo}..."
aws s3 cp ${file} ${s3_bucket_repo}/${package} --acl public-read
aws s3 cp ${file}.asc ${s3_bucket_repo}/${package}.asc --acl public-read
aws cloudfront create-invalidation --distribution-id ${AWS_CLOUDFRONT_DIST_ID} --paths ${cloudfront_path}/${package}
aws cloudfront create-invalidation --distribution-id ${AWS_CLOUDFRONT_DIST_ID} --paths ${cloudfront_path}/${package}
aws cloudfront create-invalidation --distribution-id ${AWS_CLOUDFRONT_DIST_ID} --paths ${cloudfront_path}/${package}.asc

View File

@@ -121,6 +121,47 @@ update_repo() {
popd > /dev/null
}
reduce_dir_size() {
local DIR=$1
local MAX_SIZE_GB=$2
local EXTENSION=$3
local MAX_SIZE=$((MAX_SIZE_GB*1024*1024)) # Convert GB to KB for du command
# Check if directory exists
if [[ ! -d "$DIR" ]]; then
echo "The directory $DIR does not exist."
return 1
fi
# Calculate current directory size in KB
local CUR_SIZE=$(du -sk "$DIR" | cut -f1)
# Check if we need to delete any files
if ((CUR_SIZE <= MAX_SIZE)); then
return 0
fi
# Calculate size to delete in bytes
local DEL_SIZE=$(( (CUR_SIZE - MAX_SIZE) * 1024 ))
local ACC_SIZE=0
find "$DIR" -maxdepth 1 -type f -name "*.$EXTENSION" -printf "%T+ %s %p\n" | sort | while read -r date size file; do
if ((ACC_SIZE + size < DEL_SIZE)); then
rm "$file"
ACC_SIZE=$((ACC_SIZE + size))
local asc_file="$file.asc"
if [[ -e "$asc_file" ]]; then
local asc_size=$(stat --format="%s" "$asc_file")
rm "$asc_file"
ACC_SIZE=$((ACC_SIZE + asc_size))
fi
else
break
fi
done
}
# parse options
while getopts ":f::r::s" opt; do
case "${opt}" in
@@ -188,6 +229,11 @@ if [ "${sign_all}" ]; then
sign_repo ${tmp_repo_path} ${debSuite}
fi
# remove old dev packages if necessary
if [[ ${repo} == "deb-dev" ]]; then
reduce_dir_size "${tmp_repo_path}/${debSuite}" 10 deb
fi
# update the repo by adding new packages
if ! [ ${#files[@]} -eq 0 ]; then
for file in "${files[@]}"; do
@@ -211,4 +257,10 @@ fi
# sync dists
aws s3 sync ${tmp_repo_path}/dists ${s3_bucket_repo}/dists --delete --acl public-read
aws cloudfront create-invalidation --distribution-id ${AWS_CLOUDFRONT_DIST_ID} --paths ${cloudfront_path}/dists/*
aws cloudfront create-invalidation --distribution-id ${AWS_CLOUDFRONT_DIST_ID} --paths ${cloudfront_path}/dists/*
# delete packages that have been pruned
# the dryrun option is there so we can check that we're doing the right thing, can be removed after testing
if [[ ${repo} == "deb-dev" ]]; then
aws s3 sync "${tmp_repo_path}/${debSuite}" ${s3_bucket_repo} --dryrun --delete --acl public-read
fi

View File

@@ -53,6 +53,47 @@ update_repo() {
popd > /dev/null
}
reduce_dir_size() {
local DIR=$1
local MAX_SIZE_GB=$2
local EXTENSION=$3
local MAX_SIZE=$((MAX_SIZE_GB*1024*1024)) # Convert GB to KB for du command
# Check if directory exists
if [[ ! -d "$DIR" ]]; then
echo "The directory $DIR does not exist."
return 1
fi
# Calculate current directory size in KB
local CUR_SIZE=$(du -sk "$DIR" | cut -f1)
# Check if we need to delete any files
if ((CUR_SIZE <= MAX_SIZE)); then
return 0
fi
# Calculate size to delete in bytes
local DEL_SIZE=$(( (CUR_SIZE - MAX_SIZE) * 1024 ))
local ACC_SIZE=0
find "$DIR" -maxdepth 1 -type f -name "*.$EXTENSION" -printf "%T+ %s %p\n" | sort | while read -r date size file; do
if ((ACC_SIZE + size < DEL_SIZE)); then
rm "$file"
ACC_SIZE=$((ACC_SIZE + size))
local asc_file="$file.asc"
if [[ -e "$asc_file" ]]; then
local asc_size=$(stat --format="%s" "$asc_file")
rm "$asc_file"
ACC_SIZE=$((ACC_SIZE + asc_size))
fi
else
break
fi
done
}
# parse options
while getopts ":f::r::s" opt; do
case "${opt}" in
@@ -115,6 +156,11 @@ if [ "${sign_all}" ]; then
sign_repo ${tmp_repo_path}
fi
# remove old dev packages if necessary
if [[ ${repo} == "rpm-dev" ]]; then
reduce_dir_size ${tmp_repo_path} 10 rpm
fi
# update the repo by adding new packages
if ! [ ${#files[@]} -eq 0 ]; then
for file in "${files[@]}"; do
@@ -138,4 +184,10 @@ fi
# sync repodata
aws s3 sync ${tmp_repo_path}/repodata ${s3_bucket_repo}/repodata --delete --acl public-read
aws cloudfront create-invalidation --distribution-id ${AWS_CLOUDFRONT_DIST_ID} --paths ${cloudfront_path}/repodata/*
aws cloudfront create-invalidation --distribution-id ${AWS_CLOUDFRONT_DIST_ID} --paths ${cloudfront_path}/repodata/*
# delete packages that have been pruned
# the dryrun option is there so we can check that we're doing the right thing, can be removed after testing
if [[ ${repo} == "rpm-dev" ]]; then
aws s3 sync ${tmp_repo_path} ${s3_bucket_repo} --dryrun --delete --acl public-read
fi

38
scripts/publish-wasm Executable file
View File

@@ -0,0 +1,38 @@
#!/usr/bin/env bash
set -e
usage() {
echo "usage: $0 -f <package.tar.gz>"
exit 1
}
# parse options
while getopts ":f:" opt; do
case "${opt}" in
f )
file=${OPTARG}
;;
\?)
echo "invalid option: ${OPTARG}" >&2
exit 1
;;
esac
done
shift $((OPTIND-1))
if [ -z "${file}" ]; then
usage
fi
repo="wasm-dev"
# settings
s3_bucket_repo="s3://falco-distribution/packages/${repo}"
cloudfront_path="/packages/${repo}"
# publish
package=$(basename -- ${file})
echo "Publishing ${package} to ${s3_bucket_repo}..."
aws s3 cp ${file} ${s3_bucket_repo}/${package} --acl public-read
aws cloudfront create-invalidation --distribution-id ${AWS_CLOUDFRONT_DIST_ID} --paths ${cloudfront_path}/${package}

View File

@@ -16,7 +16,10 @@
# limitations under the License.
#
chosen_driver=
# By default, we use the automatic selection for drivers
chosen_driver="auto"
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,39 +38,76 @@ 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
# "auto" case is not managed here since it is already the default, so no CHOICE=2
case $FALCO_DRIVER_CHOICE in
none)
CHOICE=1
;;
kmod)
CHOICE=3
;;
ebpf)
CHOICE=4
;;
modern_ebpf)
CHOICE=5
;;
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 "Automatic selection" \
3 "Kmod" \
4 "eBPF" \
5 "Modern eBPF" \
2>&1 >/dev/tty)
case $CHOICE in
2)
chosen_driver="kmod"
;;
3)
chosen_driver="bpf"
;;
4)
chosen_driver="modern-bpf"
fi
# "auto" case is not managed here since it is already the default, so no CHOICE=2
case $CHOICE in
1)
chosen_driver=""
;;
3)
chosen_driver="kmod"
;;
4)
chosen_driver="ebpf"
;;
5)
chosen_driver="modern_ebpf"
;;
esac
if [ -n "$chosen_driver" ]; then
echo "[POST-INSTALL] Configure falcoctl '$chosen_driver' driver type:"
if [ "$chosen_driver" = "auto" ]; then
# Configure falcoctl to enable all drivers
falcoctl driver config --type "modern_ebpf" --type "kmod" --type "ebpf"
# Load the actually automatic chosen driver
chosen_driver=$(falcoctl driver printenv | grep DRIVER= | cut -d'"' -f2)
else
falcoctl driver config --type "$chosen_driver"
fi
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 +115,21 @@ 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
chosen_unit="kmod"
;;
"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
chosen_unit="bpf"
;;
"modern_ebpf")
chosen_unit="modern-bpf"
;;
esac
@@ -95,14 +140,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

@@ -19,68 +19,62 @@ include(FetchContent)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG release-1.12.1
GIT_TAG v1.14.0
)
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"
${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
add_executable(falco_unit_tests
test_falco_engine.cpp
engine/test_add_source.cpp
engine/test_alt_rule_loader.cpp
engine/test_enable_rule.cpp
engine/test_falco_utils.cpp
engine/test_filter_details_resolver.cpp
engine/test_filter_macro_resolver.cpp
engine/test_filter_warning_resolver.cpp
engine/test_plugin_requirements.cpp
engine/test_rule_loader.cpp
engine/test_rulesets.cpp
falco/test_configuration.cpp
falco/test_configuration_rule_selection.cpp
falco/app/actions/test_select_event_sources.cpp
falco/app/actions/test_load_config.cpp
)
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
list(APPEND FALCO_UNIT_TESTS_SOURCES
falco/test_atomic_signal_handler.cpp
falco/app/actions/test_configure_interesting_sets.cpp
falco/app/actions/test_configure_syscall_buffer_num.cpp)
target_sources(falco_unit_tests
PRIVATE
falco/test_atomic_signal_handler.cpp
falco/app/actions/test_configure_interesting_sets.cpp
falco/app/actions/test_configure_syscall_buffer_num.cpp
)
endif()
set(FALCO_UNIT_TESTS_INCLUDES
PRIVATE
target_include_directories(falco_unit_tests
PRIVATE
${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
gtest
gtest_main
falco_application
${CMAKE_CURRENT_BINARY_DIR} # we need it to include `falco_test_var.h`
)
get_target_property(FALCO_APPLICATION_LIBRARIES falco_application LINK_LIBRARIES)
set(FALCO_UNIT_TESTS_LIBRARIES
gtest
gtest_main
falco_application
${FALCO_APPLICATION_LIBRARIES}
target_link_libraries(falco_unit_tests
falco_application
GTest::gtest
GTest::gtest_main
${FALCO_APPLICATION_LIBRARIES}
)
message(STATUS "FALCO_UNIT_TESTS_SOURCES: ${FALCO_UNIT_TESTS_SOURCES}")
message(STATUS "FALCO_UNIT_TESTS_INCLUDES: ${FALCO_UNIT_TESTS_INCLUDES}")
message(STATUS "FALCO_UNIT_TESTS_DEPENDENCIES: ${FALCO_UNIT_TESTS_DEPENDENCIES}")
message(STATUS "FALCO_UNIT_TESTS_LIBRARIES: ${FALCO_UNIT_TESTS_LIBRARIES}")
add_executable(falco_unit_tests ${FALCO_UNIT_TESTS_SOURCES})
target_include_directories(falco_unit_tests ${FALCO_UNIT_TESTS_INCLUDES})
target_link_libraries(falco_unit_tests ${FALCO_UNIT_TESTS_LIBRARIES})
add_dependencies(falco_unit_tests ${FALCO_UNIT_TESTS_DEPENDENCIES})
if (EMSCRIPTEN)
target_compile_options(falco_unit_tests PRIVATE "-sDISABLE_EXCEPTION_CATCHING=0")
target_link_options(falco_unit_tests PRIVATE "-sDISABLE_EXCEPTION_CATCHING=0")

View File

@@ -0,0 +1,86 @@
// 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:
explicit test_ruleset_factory(std::shared_ptr<sinsp_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::make_shared<sinsp_filter_factory>(&inspector, filterchecks);
auto formatter_factory = std::make_shared<sinsp_evt_formatter_factory>(&inspector, filterchecks);
auto ruleset_factory = std::make_shared<test_ruleset_factory>(filter_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), ruleset_factory->ruleset);
ASSERT_EQ(engine.ruleset_for_source(source_idx), ruleset_factory->ruleset);
}

View File

@@ -0,0 +1,353 @@
// 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 <eventformatter.h>
#include <falco_engine.h>
#include "indexed_vector.h"
#include "evttype_index_ruleset.h"
#include "rule_loader_reader.h"
#include "rule_loader_collector.h"
#include "rule_loader_compiler.h"
namespace
{
struct test_object_info
{
std::string name;
std::string property;
};
struct test_compile_output : public rule_loader::compile_output
{
test_compile_output() = default;
~test_compile_output() = default;
std::set<std::string> defined_test_properties;
};
class test_compiler : public rule_loader::compiler
{
public:
test_compiler() = default;
virtual ~test_compiler() = default;
std::unique_ptr<rule_loader::compile_output> new_compile_output() override
{
return std::make_unique<test_compile_output>();
}
void compile(
rule_loader::configuration& cfg,
const rule_loader::collector& col,
rule_loader::compile_output& out) const override;
};
class test_collector : public rule_loader::collector
{
public:
test_collector() = default;
virtual ~test_collector() = default;
indexed_vector<test_object_info> test_object_infos;
};
class test_reader : public rule_loader::reader
{
public:
test_reader() = default;
virtual ~test_reader() = default;
protected:
rule_loader::context create_context(const YAML::Node& item,
const rule_loader::context& parent)
{
return rule_loader::context(item,
rule_loader::context::EXTENSION_ITEM,
"test object",
parent);
};
void read_item(rule_loader::configuration& cfg,
rule_loader::collector& collector,
const YAML::Node& item,
const rule_loader::context& parent) override
{
test_collector& test_col =
dynamic_cast<test_collector&>(collector);
if(item["test_object"].IsDefined())
{
rule_loader::context tmp = create_context(item, parent);
test_object_info obj;
std::string name;
std::string property;
decode_val(item, "test_object", name, tmp);
decode_val(item, "property", property, tmp);
obj.name = name;
obj.property = property;
test_col.test_object_infos.insert(obj, obj.name);
}
else
{
rule_loader::reader::read_item(cfg, collector, item, parent);
}
};
};
class test_ruleset : public evttype_index_ruleset
{
public:
explicit test_ruleset(std::shared_ptr<sinsp_filter_factory> factory):
evttype_index_ruleset(factory){};
virtual ~test_ruleset() = default;
void add_compile_output(
const rule_loader::compile_output& compile_output,
falco_common::priority_type min_priority,
const std::string& source)
{
evttype_index_ruleset::add_compile_output(compile_output,
min_priority,
source);
std::shared_ptr<filter_ruleset> ruleset;
get_engine_state().get_ruleset(source, ruleset);
EXPECT_EQ(this, ruleset.get());
const test_compile_output& test_output =
dynamic_cast<const test_compile_output&>(compile_output);
defined_properties = test_output.defined_test_properties;
};
std::set<std::string> defined_properties;
};
class test_ruleset_factory : public filter_ruleset_factory
{
public:
explicit test_ruleset_factory(std::shared_ptr<sinsp_filter_factory> factory):
m_filter_factory(factory)
{
}
virtual ~test_ruleset_factory() = default;
inline std::shared_ptr<filter_ruleset> new_ruleset() override
{
return std::make_shared<test_ruleset>(m_filter_factory);
}
std::shared_ptr<sinsp_filter_factory> m_filter_factory;
};
}; // namespace
void test_compiler::compile(
rule_loader::configuration& cfg,
const rule_loader::collector& col,
rule_loader::compile_output& out) const
{
rule_loader::compiler::compile(cfg, col, out);
const test_collector& test_col =
dynamic_cast<const test_collector&>(col);
test_compile_output& test_output =
dynamic_cast<test_compile_output&>(out);
for(auto& test_obj : test_col.test_object_infos)
{
test_output.defined_test_properties.insert(test_obj.property);
}
}
static std::string content = R"END(
- test_object: test
property: my-value
- test_object: test2
property: other-value
- list: shell_binaries
items: [sh, bash]
- macro: spawned_process
condition: evt.type=execve and proc.name in (shell_binaries)
- rule: test info rule
desc: A test info rule
condition: spawned_process
output: A test info rule matched (evt.type=%evt.type proc.name=%proc.name)
priority: INFO
source: syscall
tags: [process]
- rule: test k8s_audit rule
desc: A k8s audit test rule
condition: ka.target.resource=deployments
output: A k8s audit rule matched (ka.verb=%ka.verb resource=%ka.target.resource)
priority: INFO
source: k8s_audit
tags: [process]
- rule: test debug rule
desc: A test debug rule
condition: spawned_process and proc.name="bash"
output: A test debug rule matched (evt.type=%evt.type proc.name=%proc.name)
priority: DEBUG
source: syscall
tags: [process]
)END";
static std::string syscall_source_name = "syscall";
static std::shared_ptr<rule_loader::configuration> create_configuration(sinsp& inspector,
sinsp_filter_check_list& filterchecks,
indexed_vector<falco_source>& sources)
{
auto filter_factory = std::make_shared<sinsp_filter_factory>(&inspector, filterchecks);
auto formatter_factory = std::make_shared<sinsp_evt_formatter_factory>(&inspector, filterchecks);
auto ruleset_factory = std::make_shared<evttype_index_ruleset_factory>(filter_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;
sources.insert(syscall_source, syscall_source_name);
return std::make_shared<rule_loader::configuration>(content,
sources,
"test configuration");
}
static void load_rules(sinsp& inspector,
sinsp_filter_check_list& filterchecks,
std::unique_ptr<rule_loader::compile_output>& compile_output,
indexed_vector<falco_source>& sources)
{
std::shared_ptr<rule_loader::configuration> cfg = create_configuration(inspector, filterchecks, sources);
rule_loader::reader reader;
rule_loader::collector collector;
rule_loader::compiler compiler;
EXPECT_TRUE(reader.read(*cfg, collector));
compile_output = compiler.new_compile_output();
compiler.compile(*cfg, collector, *compile_output);
}
TEST(engine_loader_alt_loader, load_rules)
{
sinsp inspector;
sinsp_filter_check_list filterchecks;
std::unique_ptr<rule_loader::compile_output> compile_output;
indexed_vector<falco_source> sources;
load_rules(inspector, filterchecks, compile_output, sources);
// Note that the k8s_audit rule will be skipped as load_rules
// only adds a syscall source.
EXPECT_EQ(compile_output->lists.size(), 1);
EXPECT_TRUE(compile_output->lists.at("shell_binaries") != nullptr);
EXPECT_EQ(compile_output->macros.size(), 1);
EXPECT_TRUE(compile_output->macros.at("spawned_process") != nullptr);
EXPECT_EQ(compile_output->rules.size(), 2);
EXPECT_TRUE(compile_output->rules.at("test info rule") != nullptr);
EXPECT_TRUE(compile_output->rules.at("test debug rule") != nullptr);
}
TEST(engine_loader_alt_loader, pass_compile_output_to_ruleset)
{
sinsp inspector;
sinsp_filter_check_list filterchecks;
std::unique_ptr<rule_loader::compile_output> compile_output;
indexed_vector<falco_source> sources;
load_rules(inspector, filterchecks, compile_output, sources);
std::shared_ptr<filter_ruleset> ruleset = sources.at(syscall_source_name)->ruleset;
ruleset->add_compile_output(*compile_output,
falco_common::PRIORITY_INFORMATIONAL,
syscall_source_name);
// Enable all rules for a ruleset id. Because the compile
// output contained one rule with priority >= INFO, that rule
// should be enabled.
uint16_t ruleset_id = 0;
ruleset->enable("", filter_ruleset::match_type::substring, ruleset_id);
EXPECT_EQ(ruleset->enabled_count(ruleset_id), 1);
}
TEST(engine_loader_alt_loader, falco_engine_alternate_loader)
{
falco_engine engine;
sinsp inspector;
sinsp_filter_check_list filterchecks;
auto filter_factory = std::make_shared<sinsp_filter_factory>(&inspector, filterchecks);
auto formatter_factory = std::make_shared<sinsp_evt_formatter_factory>(&inspector, filterchecks);
auto ruleset_factory = std::make_shared<test_ruleset_factory>(filter_factory);
engine.add_source(syscall_source_name, filter_factory, formatter_factory, ruleset_factory);
auto reader = std::make_shared<test_reader>();
auto collector = std::make_shared<test_collector>();
auto compiler = std::make_shared<test_compiler>();
engine.set_rule_reader(reader);
engine.set_rule_collector(collector);
engine.set_rule_compiler(compiler);
EXPECT_EQ(reader, engine.get_rule_reader());
EXPECT_EQ(collector, engine.get_rule_collector());
EXPECT_EQ(compiler, engine.get_rule_compiler());
engine.load_rules(content, "test_rules.yaml");
EXPECT_EQ(collector->test_object_infos.size(), 2);
std::shared_ptr<filter_ruleset> ruleset = engine.ruleset_for_source(syscall_source_name);
std::set<std::string>& defined_properties = std::dynamic_pointer_cast<test_ruleset>(ruleset)->defined_properties;
EXPECT_TRUE(defined_properties.find("my-value") != defined_properties.end());
EXPECT_TRUE(defined_properties.find("other-value") != defined_properties.end());
EXPECT_TRUE(defined_properties.find("not-exists-value") == defined_properties.end());
};

View File

@@ -0,0 +1,286 @@
// 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 "../test_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";
static std::string multi_rule = R"END(
- rule: first actual 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: second disabled rule
desc: A disabled rule
condition: evt.type=execve
output: A disabled 2 rule matched (evt.type=%evt.type)
priority: INFO
source: syscall
enabled: false
tags: [exec process]
- rule: third disabled rule
desc: A disabled rule
condition: evt.type=execve
output: A disabled 3 rule matched (evt.type=%evt.type)
priority: INFO
source: syscall
enabled: false
tags: [exec]
)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";
TEST_F(test_falco_engine, enable_rule_name)
{
load_rules(single_rule, "single_rule.yaml");
// No rules should be enabled yet for any custom rulesets
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(default_ruleset));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_3));
// Enable for first ruleset, only that ruleset should have an
// enabled rule afterward
m_engine->enable_rule("test", true, ruleset_1);
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_3));
// Enable for second ruleset
m_engine->enable_rule("test", true, ruleset_2);
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_3));
// When the substring is blank, all rules are enabled
// (including the disabled rule)
m_engine->enable_rule("", true, ruleset_3);
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(2, m_engine->num_rules_for_ruleset(ruleset_3));
// Now disable for second ruleset
m_engine->enable_rule("test", false, ruleset_2);
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(2, m_engine->num_rules_for_ruleset(ruleset_3));
}
TEST_F(test_falco_engine, enable_rule_tags)
{
std::set<std::string> process_tags = {"process"};
load_rules(single_rule, "single_rule.yaml");
// No rules should be enabled yet for any custom rulesets
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(default_ruleset));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_2));
// Enable for first ruleset, only that ruleset should have an
// enabled rule afterward
m_engine->enable_rule_by_tag(process_tags, true, ruleset_1);
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_2));
// Enable for second ruleset
m_engine->enable_rule_by_tag(process_tags, true, ruleset_2);
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_2));
// Now disable for second ruleset
m_engine->enable_rule_by_tag(process_tags, false, ruleset_2);
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_2));
}
TEST_F(test_falco_engine, enable_disabled_rule_by_tag)
{
std::set<std::string> exec_process_tags = {"exec process"};
load_rules(single_rule, "single_rule.yaml");
// Only the first rule should be enabled
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(default_ruleset));
// Enable the disabled rule by tag
m_engine->enable_rule_by_tag(exec_process_tags, true);
// Both rules should be enabled now
EXPECT_EQ(2, m_engine->num_rules_for_ruleset(default_ruleset));
}
TEST_F(test_falco_engine, enable_rule_id)
{
uint16_t ruleset_1_id;
uint16_t ruleset_2_id;
uint16_t ruleset_3_id;
load_rules(single_rule, "single_rule.yaml");
// The cases are identical to above, just using ruleset ids
// instead of names.
ruleset_1_id = m_engine->find_ruleset_id(ruleset_1);
ruleset_2_id = m_engine->find_ruleset_id(ruleset_2);
ruleset_3_id = m_engine->find_ruleset_id(ruleset_3);
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(default_ruleset));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_3));
m_engine->enable_rule("test rule", true, ruleset_1_id);
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_3));
m_engine->enable_rule("test rule", true, ruleset_2_id);
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_3));
m_engine->enable_rule("", true, ruleset_3_id);
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(2, m_engine->num_rules_for_ruleset(ruleset_3));
m_engine->enable_rule("test", false, ruleset_2_id);
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(2, m_engine->num_rules_for_ruleset(ruleset_3));
}
TEST_F(test_falco_engine, enable_rule_name_exact)
{
load_rules(single_rule, "single_rule.yaml");
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(default_ruleset));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_3));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_4));
m_engine->enable_rule_exact("test rule", true, ruleset_1);
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_3));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_4));
m_engine->enable_rule_exact("test rule", true, ruleset_2);
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_3));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_4));
// This should **not** enable as this is a substring and not
// an exact match.
m_engine->enable_rule_exact("test", true, ruleset_3);
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_3));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_4));
m_engine->enable_rule_exact("", true, ruleset_4);
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_3));
EXPECT_EQ(2, m_engine->num_rules_for_ruleset(ruleset_4));
m_engine->enable_rule("test rule", false, ruleset_2);
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_3));
EXPECT_EQ(2, m_engine->num_rules_for_ruleset(ruleset_4));
}
TEST_F(test_falco_engine, enable_rule_name_wildcard)
{
load_rules(multi_rule, "multi_rule.yaml");
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(default_ruleset));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_3));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_4));
// As long as there are no *, exact matches work
m_engine->enable_rule_wildcard("first actual rule", true, ruleset_1);
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_3));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_4));
m_engine->enable_rule_wildcard("*rule", true, ruleset_2);
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(3, m_engine->num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_3));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_4));
// This should enable the second rule
m_engine->enable_rule_wildcard("*second*r*", true, ruleset_3);
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(3, m_engine->num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_3));
EXPECT_EQ(0, m_engine->num_rules_for_ruleset(ruleset_4));
m_engine->enable_rule_wildcard("*", true, ruleset_4);
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_1));
EXPECT_EQ(3, m_engine->num_rules_for_ruleset(ruleset_2));
EXPECT_EQ(1, m_engine->num_rules_for_ruleset(ruleset_3));
EXPECT_EQ(3, m_engine->num_rules_for_ruleset(ruleset_4));
}

View File

@@ -73,21 +73,31 @@ TEST(FalcoUtils, parse_prometheus_interval)
ASSERT_EQ(falco::utils::parse_prometheus_interval("200"), 0UL);
}
TEST(FalcoUtils, decode_url)
TEST(FalcoUtils, sanitize_metric_name)
{
ASSERT_EQ(
falco::utils::decode_uri("https://www.example.com?key1=value+1&key2=value%40%21%242&key3=value%253", true),
"https://www.example.com?key1=value 1&key2=value@!$2&key3=value%3");
ASSERT_EQ(
falco::utils::decode_uri("https://download.falco.org/?prefix=driver/3.0.1%2Bdriver/x86_64/", true),
"https://download.falco.org/?prefix=driver/3.0.1+driver/x86_64/");
ASSERT_EQ(
falco::utils::decode_uri("https://example.com/hello%20world", true),
"https://example.com/hello world");
ASSERT_EQ(
falco::utils::decode_uri("https://example.com/helloworld", true),
"https://example.com/helloworld");
ASSERT_EQ(falco::utils::sanitize_metric_name("Testing rule 2 (CVE-2244)"), "Testing_rule_2_CVE_2244");
ASSERT_EQ(falco::utils::sanitize_metric_name("Testing rule__:2)"), "Testing_rule_:2");
ASSERT_EQ(falco::utils::sanitize_metric_name("This@is_a$test rule123"), "This_is_a_test_rule123");
ASSERT_EQ(falco::utils::sanitize_metric_name("RULEwith:special#characters"), "RULEwith:special_characters");
}
TEST(FalcoUtils, matches_wildcard)
{
ASSERT_TRUE(falco::utils::matches_wildcard("*", "anything"));
ASSERT_TRUE(falco::utils::matches_wildcard("**", "anything"));
ASSERT_TRUE(falco::utils::matches_wildcard("*", ""));
ASSERT_TRUE(falco::utils::matches_wildcard("no star", "no star"));
ASSERT_TRUE(falco::utils::matches_wildcard("", ""));
ASSERT_TRUE(falco::utils::matches_wildcard("hello*world", "hello new world"));
ASSERT_TRUE(falco::utils::matches_wildcard("hello*world*", "hello new world yes"));
ASSERT_TRUE(falco::utils::matches_wildcard("*hello*world", "come on hello this world"));
ASSERT_TRUE(falco::utils::matches_wildcard("*hello*****world", "come on hello this world"));
ASSERT_FALSE(falco::utils::matches_wildcard("no star", ""));
ASSERT_FALSE(falco::utils::matches_wildcard("", "no star"));
ASSERT_FALSE(falco::utils::matches_wildcard("star", "no star"));
ASSERT_FALSE(falco::utils::matches_wildcard("hello*world", "hello new thing"));
ASSERT_FALSE(falco::utils::matches_wildcard("hello*world", "hello new world yes"));
ASSERT_FALSE(falco::utils::matches_wildcard("*hello*world", "come on hello this world yes"));
ASSERT_FALSE(falco::utils::matches_wildcard("*hello*world*", "come on hello this yes"));
}

View File

@@ -8,7 +8,7 @@ You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless ASSERT_EQd by applicable law or agreed to in writing, software
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
@@ -18,6 +18,8 @@ limitations under the License.
#include <gtest/gtest.h>
#include <engine/filter_macro_resolver.h>
namespace filter_ast = libsinsp::filter::ast;
static std::vector<filter_macro_resolver::value_info>::const_iterator find_value(
const std::vector<filter_macro_resolver::value_info>& values,
const std::string& ref)
@@ -35,19 +37,19 @@ static std::vector<filter_macro_resolver::value_info>::const_iterator find_value
TEST(MacroResolver, should_resolve_macros_on_a_filter_AST)
{
libsinsp::filter::ast::pos_info macro_pos(12, 85, 27);
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<filter_ast::expr> macro = filter_ast::unary_check_expr::create(filter_ast::field_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::vector<std::unique_ptr<filter_ast::expr>> filter_and;
filter_and.push_back(filter_ast::unary_check_expr::create(filter_ast::field_expr::create("evt.name", ""), "exists"));
filter_and.push_back(filter_ast::not_expr::create(filter_ast::identifier_expr::create(MACRO_NAME, macro_pos)));
std::shared_ptr<filter_ast::expr> filter = 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::vector<std::unique_ptr<filter_ast::expr>> expected_and;
expected_and.push_back(filter_ast::unary_check_expr::create(filter_ast::field_expr::create("evt.name", ""), "exists"));
expected_and.push_back(filter_ast::not_expr::create(clone(macro.get())));
std::shared_ptr<filter_ast::expr> expected = filter_ast::and_expr::create(expected_and);
filter_macro_resolver resolver;
resolver.set_macro(MACRO_NAME, macro);
@@ -69,17 +71,17 @@ TEST(MacroResolver, should_resolve_macros_on_a_filter_AST)
TEST(MacroResolver, should_resolve_macros_on_a_filter_AST_single_node)
{
libsinsp::filter::ast::pos_info macro_pos(12, 85, 27);
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<filter_ast::expr> macro = filter_ast::unary_check_expr::create(filter_ast::field_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<filter_ast::expr> filter = filter_ast::identifier_expr::create(MACRO_NAME, macro_pos);
filter_macro_resolver resolver;
resolver.set_macro(MACRO_NAME, macro);
// first run
libsinsp::filter::ast::expr* old_filter_ptr = filter.get();
filter_ast::expr* old_filter_ptr = filter.get();
ASSERT_TRUE(resolver.run(filter));
ASSERT_NE(filter.get(), old_filter_ptr);
ASSERT_EQ(resolver.get_resolved_macros().size(), 1);
@@ -99,21 +101,21 @@ TEST(MacroResolver, should_resolve_macros_on_a_filter_AST_single_node)
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);
filter_ast::pos_info a_macro_pos(11, 75, 43);
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<filter_ast::expr> a_macro = filter_ast::unary_check_expr::create(filter_ast::field_expr::create("one.field", ""), "exists");
std::shared_ptr<filter_ast::expr> b_macro = filter_ast::unary_check_expr::create(filter_ast::field_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::vector<std::unique_ptr<filter_ast::expr>> filter_or;
filter_or.push_back(filter_ast::identifier_expr::create(MACRO_A_NAME, a_macro_pos));
filter_or.push_back(filter_ast::identifier_expr::create(MACRO_B_NAME, b_macro_pos));
std::shared_ptr<filter_ast::expr> filter = filter_ast::or_expr::create(filter_or);
std::vector<std::unique_ptr<libsinsp::filter::ast::expr>> expected_or;
std::vector<std::unique_ptr<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<filter_ast::expr> expected_filter = filter_ast::or_expr::create(expected_or);
filter_macro_resolver resolver;
resolver.set_macro(MACRO_A_NAME, a_macro);
@@ -143,23 +145,23 @@ TEST(MacroResolver, should_resolve_macros_on_a_filter_AST_multiple_macros)
TEST(MacroResolver, should_resolve_macros_on_a_filter_AST_nested_macros)
{
libsinsp::filter::ast::pos_info a_macro_pos(47, 1, 76);
libsinsp::filter::ast::pos_info b_macro_pos(111, 65, 2);
filter_ast::pos_info a_macro_pos(47, 1, 76);
filter_ast::pos_info b_macro_pos(111, 65, 2);
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::vector<std::unique_ptr<filter_ast::expr>> a_macro_and;
a_macro_and.push_back(filter_ast::unary_check_expr::create(filter_ast::field_expr::create("one.field", ""), "exists"));
a_macro_and.push_back(filter_ast::identifier_expr::create(MACRO_B_NAME, b_macro_pos));
std::shared_ptr<filter_ast::expr> a_macro = 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<filter_ast::expr> b_macro =
filter_ast::unary_check_expr::create(filter_ast::field_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<filter_ast::expr> filter = filter_ast::identifier_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::vector<std::unique_ptr<filter_ast::expr>> expected_and;
expected_and.push_back(filter_ast::unary_check_expr::create(filter_ast::field_expr::create("one.field", ""), "exists"));
expected_and.push_back(filter_ast::unary_check_expr::create(filter_ast::field_expr::create("another.field", ""), "exists"));
std::shared_ptr<filter_ast::expr> expected_filter = filter_ast::and_expr::create(expected_and);
filter_macro_resolver resolver;
resolver.set_macro(MACRO_A_NAME, a_macro);
@@ -191,12 +193,12 @@ TEST(MacroResolver, should_resolve_macros_on_a_filter_AST_nested_macros)
TEST(MacroResolver, should_find_unknown_macros)
{
libsinsp::filter::ast::pos_info macro_pos(9, 4, 2);
filter_ast::pos_info macro_pos(9, 4, 2);
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::vector<std::unique_ptr<filter_ast::expr>> filter_and;
filter_and.push_back(filter_ast::unary_check_expr::create(filter_ast::field_expr::create("evt.name", ""), "exists"));
filter_and.push_back(filter_ast::not_expr::create(filter_ast::identifier_expr::create(MACRO_NAME, macro_pos)));
std::shared_ptr<filter_ast::expr> filter = filter_ast::and_expr::create(filter_and);
filter_macro_resolver resolver;
ASSERT_FALSE(resolver.run(filter));
@@ -208,15 +210,15 @@ TEST(MacroResolver, should_find_unknown_macros)
TEST(MacroResolver, should_find_unknown_nested_macros)
{
libsinsp::filter::ast::pos_info a_macro_pos(32, 84, 9);
libsinsp::filter::ast::pos_info b_macro_pos(1, 0, 5);
filter_ast::pos_info a_macro_pos(32, 84, 9);
filter_ast::pos_info b_macro_pos(1, 0, 5);
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::vector<std::unique_ptr<filter_ast::expr>> a_macro_and;
a_macro_and.push_back(filter_ast::unary_check_expr::create(filter_ast::field_expr::create("one.field", ""), "exists"));
a_macro_and.push_back(filter_ast::identifier_expr::create(MACRO_B_NAME, b_macro_pos));
std::shared_ptr<filter_ast::expr> a_macro = 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<filter_ast::expr> filter = filter_ast::identifier_expr::create(MACRO_A_NAME, a_macro_pos);
auto expected_filter = clone(a_macro.get());
filter_macro_resolver resolver;
@@ -234,12 +236,12 @@ TEST(MacroResolver, should_find_unknown_nested_macros)
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);
filter_ast::pos_info macro_pos_1(12, 9, 3);
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<filter_ast::expr> macro = filter_ast::unary_check_expr::create(filter_ast::field_expr::create("test.field", ""), "exists");
std::shared_ptr<filter_ast::expr> a_filter = filter_ast::identifier_expr::create(MACRO_NAME, macro_pos_1);
std::shared_ptr<filter_ast::expr> b_filter = filter_ast::identifier_expr::create(MACRO_NAME, macro_pos_2);
filter_macro_resolver resolver;
resolver.set_macro(MACRO_NAME, macro);
@@ -261,9 +263,9 @@ TEST(MacroResolver, should_undefine_macro)
/* checks that the macro AST is cloned and not shared across resolved filters */
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));
filter_ast::pos_info macro_pos(5, 2, 8888);
std::shared_ptr<filter_ast::unary_check_expr> macro = filter_ast::unary_check_expr::create(filter_ast::field_expr::create("test.field", ""), "exists");
std::shared_ptr<filter_ast::expr> filter = filter_ast::identifier_expr::create(MACRO_NAME, macro_pos);
filter_macro_resolver resolver;
resolver.set_macro(MACRO_NAME, macro);
@@ -274,6 +276,6 @@ TEST(MacroResolver, should_clone_macro_AST)
ASSERT_TRUE(resolver.get_unknown_macros().empty());
ASSERT_TRUE(filter->is_equal(macro.get()));
macro->field = "another.field";
macro->left = filter_ast::field_expr::create("another.field", "");
ASSERT_FALSE(filter->is_equal(macro.get()));
}

View File

@@ -8,7 +8,7 @@ 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
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

View File

@@ -23,15 +23,15 @@ static bool check_requirements(std::string& err,
const std::vector<falco_engine::plugin_version_requirement>& plugins,
const std::string& ruleset_content)
{
std::unique_ptr<falco_engine> e(new falco_engine());
falco_engine e;
falco::load_result::rules_contents_t c = {{"test", ruleset_content}};
auto res = e->load_rules(c.begin()->second, c.begin()->first);
auto res = e.load_rules(c.begin()->second, c.begin()->first);
if(!res->successful())
{
return false;
}
return e->check_plugin_requirements(plugins, err);
return e.check_plugin_requirements(plugins, err);
}
TEST(PluginRequirements, check_plugin_requirements_success)

File diff suppressed because it is too large Load Diff

View File

@@ -23,41 +23,39 @@ limitations under the License.
#define RULESET_2 2
/* Helpers methods */
static std::shared_ptr<gen_event_filter_factory> create_factory(filter_check_list& list)
static std::shared_ptr<sinsp_filter_factory> create_factory(sinsp* inspector, filter_check_list& list)
{
std::shared_ptr<gen_event_filter_factory> ret(new sinsp_filter_factory(NULL, list));
return ret;
return std::make_shared<sinsp_filter_factory>(inspector, list);
}
static std::shared_ptr<filter_ruleset> create_ruleset(std::shared_ptr<gen_event_filter_factory> f)
static std::shared_ptr<filter_ruleset> create_ruleset(std::shared_ptr<sinsp_filter_factory> f)
{
std::shared_ptr<filter_ruleset> ret(new evttype_index_ruleset(f));
return ret;
return std::make_shared<evttype_index_ruleset>(f);
}
static std::shared_ptr<libsinsp::filter::ast::expr> create_ast(std::shared_ptr<gen_event_filter_factory> f)
static std::shared_ptr<libsinsp::filter::ast::expr> create_ast(std::shared_ptr<sinsp_filter_factory> f)
{
libsinsp::filter::parser parser("evt.type=open");
std::shared_ptr<libsinsp::filter::ast::expr> ret(parser.parse());
return ret;
return parser.parse();
}
static std::shared_ptr<gen_event_filter> create_filter(
std::shared_ptr<gen_event_filter_factory> f,
std::shared_ptr<libsinsp::filter::ast::expr> ast)
static std::shared_ptr<sinsp_filter> create_filter(
std::shared_ptr<sinsp_filter_factory> f,
libsinsp::filter::ast::expr* ast)
{
sinsp_filter_compiler compiler(f, ast.get());
std::shared_ptr<gen_event_filter> filter(compiler.compile());
return filter;
sinsp_filter_compiler compiler(f, ast);
return std::shared_ptr<sinsp_filter>(compiler.compile());
}
TEST(Ruleset, enable_disable_rules_using_names)
{
sinsp inspector;
sinsp_filter_check_list filterlist;
auto f = create_factory(filterlist);
auto f = create_factory(&inspector, filterlist);
auto r = create_ruleset(f);
auto ast = create_ast(f);
auto filter = create_filter(f, ast);
auto filter = create_filter(f, ast.get());
falco_rule rule_A = {};
rule_A.name = "rule_A";
@@ -76,55 +74,81 @@ TEST(Ruleset, enable_disable_rules_using_names)
r->add(rule_C, filter, ast);
/* Enable `rule_A` for RULESET_0 */
r->enable(rule_A.name, true, RULESET_0);
r->enable(rule_A.name, filter_ruleset::match_type::exact, RULESET_0);
ASSERT_EQ(r->enabled_count(RULESET_0), 1);
ASSERT_EQ(r->enabled_count(RULESET_1), 0);
ASSERT_EQ(r->enabled_count(RULESET_2), 0);
/* Disable `rule_A` for RULESET_1, this should have no effect */
r->disable(rule_A.name, true, RULESET_1);
r->disable(rule_A.name, filter_ruleset::match_type::exact, RULESET_1);
ASSERT_EQ(r->enabled_count(RULESET_0), 1);
ASSERT_EQ(r->enabled_count(RULESET_1), 0);
ASSERT_EQ(r->enabled_count(RULESET_2), 0);
/* Enable a not existing rule for RULESET_2, this should have no effect */
r->disable("<NA>", true, RULESET_2);
r->disable("<NA>", filter_ruleset::match_type::exact, RULESET_2);
ASSERT_EQ(r->enabled_count(RULESET_0), 1);
ASSERT_EQ(r->enabled_count(RULESET_1), 0);
ASSERT_EQ(r->enabled_count(RULESET_2), 0);
/* Enable all rules for RULESET_0 */
r->enable("rule_", false, RULESET_0);
r->enable("rule_", filter_ruleset::match_type::substring, RULESET_0);
ASSERT_EQ(r->enabled_count(RULESET_0), 3);
ASSERT_EQ(r->enabled_count(RULESET_1), 0);
ASSERT_EQ(r->enabled_count(RULESET_2), 0);
/* Try to disable all rules with exact match for RULESET_0, this should have no effect */
r->disable("rule_", true, RULESET_0);
r->disable("rule_", filter_ruleset::match_type::exact, RULESET_0);
ASSERT_EQ(r->enabled_count(RULESET_0), 3);
ASSERT_EQ(r->enabled_count(RULESET_1), 0);
ASSERT_EQ(r->enabled_count(RULESET_2), 0);
/* Disable all rules for RULESET_0 */
r->disable("rule_", false, RULESET_0);
r->disable("rule_", filter_ruleset::match_type::substring, RULESET_0);
ASSERT_EQ(r->enabled_count(RULESET_0), 0);
ASSERT_EQ(r->enabled_count(RULESET_1), 0);
ASSERT_EQ(r->enabled_count(RULESET_2), 0);
/* Enable rule_C for RULESET_2 without exact_match */
r->enable("_C", false, RULESET_2);
r->enable("_C", filter_ruleset::match_type::substring, RULESET_2);
ASSERT_EQ(r->enabled_count(RULESET_0), 0);
ASSERT_EQ(r->enabled_count(RULESET_1), 0);
ASSERT_EQ(r->enabled_count(RULESET_2), 1);
/* Disable rule_C for RULESET_2 without exact_match */
r->disable("_C", filter_ruleset::match_type::substring, RULESET_2);
ASSERT_EQ(r->enabled_count(RULESET_0), 0);
ASSERT_EQ(r->enabled_count(RULESET_1), 0);
ASSERT_EQ(r->enabled_count(RULESET_2), 0);
/* Enable all rules for RULESET_0 with wildcard */
r->enable("*", filter_ruleset::match_type::wildcard, RULESET_0);
ASSERT_EQ(r->enabled_count(RULESET_0), 3);
ASSERT_EQ(r->enabled_count(RULESET_1), 0);
ASSERT_EQ(r->enabled_count(RULESET_2), 0);
/* Disable rule C for RULESET_0 with wildcard */
r->disable("*C*", filter_ruleset::match_type::wildcard, RULESET_0);
ASSERT_EQ(r->enabled_count(RULESET_0), 2);
ASSERT_EQ(r->enabled_count(RULESET_1), 0);
ASSERT_EQ(r->enabled_count(RULESET_2), 0);
/* Disable all rules for RULESET_0 with wildcard */
r->disable("*_*", filter_ruleset::match_type::wildcard, RULESET_0);
ASSERT_EQ(r->enabled_count(RULESET_0), 0);
ASSERT_EQ(r->enabled_count(RULESET_1), 0);
ASSERT_EQ(r->enabled_count(RULESET_2), 0);
}
TEST(Ruleset, enable_disable_rules_using_tags)
{
sinsp inspector;
sinsp_filter_check_list filterlist;
auto f = create_factory(filterlist);
auto f = create_factory(&inspector, filterlist);
auto r = create_ruleset(f);
auto ast = create_ast(f);
auto filter = create_filter(f, ast);
auto filter = create_filter(f, ast.get());
falco_rule rule_A = {};
rule_A.name = "rule_A";

View File

@@ -16,7 +16,9 @@ limitations under the License.
*/
#include <falco_engine.h>
#include "../../../test_falco_engine.h"
#include <utility>
#include <falco/app/app.h>
#include "app_action_helpers.h"
@@ -57,14 +59,11 @@ static strset_t s_sample_nonsyscall_filters = {
"evt.type in (procexit, switch, pluginevent, container)"};
// todo(jasondellaluce): once we have deeper and more modular
// control on the falco engine, make this a little nicer
static std::shared_ptr<falco_engine> mock_engine_from_filters(const strset_t& filters)
static std::string ruleset_from_filters(const strset_t& filters)
{
// craft a fake ruleset with the given filters
int n_rules = 0;
std::string dummy_rules;
falco::load_result::rules_contents_t content = {{"dummy_rules.yaml", dummy_rules}};
int n_rules = 0;
for (const auto& f : filters)
{
n_rules++;
@@ -76,28 +75,18 @@ static std::shared_ptr<falco_engine> mock_engine_from_filters(const strset_t& fi
+ " priority: CRITICAL\n\n";
}
// 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, filterlist));
auto formatter_factory = std::shared_ptr<gen_event_formatter_factory>(
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);
return res;
return dummy_rules;
}
TEST(ConfigureInterestingSets, engine_codes_syscalls_set)
TEST_F(test_falco_engine, engine_codes_syscalls_set)
{
load_rules(ruleset_from_filters(s_sample_filters), "dummy_ruleset.yaml");
auto engine = mock_engine_from_filters(s_sample_filters);
auto enabled_count = engine->num_rules_for_ruleset(s_sample_ruleset);
auto enabled_count = m_engine->num_rules_for_ruleset(s_sample_ruleset);
ASSERT_EQ(enabled_count, s_sample_filters.size());
// test if event code names were extracted from each rule in test ruleset.
auto rules_event_set = engine->event_codes_for_ruleset(s_sample_source);
auto rules_event_set = m_engine->event_codes_for_ruleset(s_sample_source);
auto rules_event_names = libsinsp::events::event_set_to_names(rules_event_set);
ASSERT_NAMES_EQ(rules_event_names, strset_t({
"connect", "accept", "accept4", "umount2", "open", "ptrace", "mmap", "execve", "read", "container", "asyncevent"}));
@@ -105,30 +94,31 @@ TEST(ConfigureInterestingSets, engine_codes_syscalls_set)
// test if sc code names were extracted from each rule in test ruleset.
// note, this is not supposed to contain "container", as that's an event
// not mapped through the ppm_sc_code enumerative.
auto rules_sc_set = engine->sc_codes_for_ruleset(s_sample_source);
auto rules_sc_set = m_engine->sc_codes_for_ruleset(s_sample_source);
auto rules_sc_names = libsinsp::events::sc_set_to_event_names(rules_sc_set);
ASSERT_NAMES_EQ(rules_sc_names, strset_t({
"connect", "accept", "accept4", "umount2", "open", "ptrace", "mmap", "execve", "read"}));
}
TEST(ConfigureInterestingSets, preconditions_postconditions)
TEST_F(test_falco_engine, preconditions_postconditions)
{
auto mock_engine = mock_engine_from_filters(s_sample_filters);
load_rules(ruleset_from_filters(s_sample_filters), "dummy_ruleset.yaml");
falco::app::state s1;
s1.engine = mock_engine;
s1.config = nullptr;
s1.engine = nullptr;
s1.config = std::make_shared<falco_configuration>();
s1.options.all_events = false;
auto result = falco::app::actions::configure_interesting_sets(s1);
ASSERT_FALSE(result.success);
ASSERT_NE(result.errstr, "");
s1.engine = nullptr;
s1.config = std::make_shared<falco_configuration>();
s1.engine = m_engine;
s1.config = nullptr;
result = falco::app::actions::configure_interesting_sets(s1);
ASSERT_FALSE(result.success);
ASSERT_NE(result.errstr, "");
s1.engine = mock_engine;
s1.config = std::make_shared<falco_configuration>();
result = falco::app::actions::configure_interesting_sets(s1);
ASSERT_TRUE(result.success);
@@ -141,17 +131,18 @@ TEST(ConfigureInterestingSets, preconditions_postconditions)
ASSERT_EQ(prev_selection_size, s1.selected_sc_set.size());
}
TEST(ConfigureInterestingSets, engine_codes_nonsyscalls_set)
TEST_F(test_falco_engine, engine_codes_nonsyscalls_set)
{
auto filters = s_sample_filters;
filters.insert(s_sample_generic_filters.begin(), s_sample_generic_filters.end());
filters.insert(s_sample_nonsyscall_filters.begin(), s_sample_nonsyscall_filters.end());
auto engine = mock_engine_from_filters(filters);
auto enabled_count = engine->num_rules_for_ruleset(s_sample_ruleset);
load_rules(ruleset_from_filters(filters), "dummy_ruleset.yaml");
auto enabled_count = m_engine->num_rules_for_ruleset(s_sample_ruleset);
ASSERT_EQ(enabled_count, filters.size());
auto rules_event_set = engine->event_codes_for_ruleset(s_sample_source);
auto rules_event_set = m_engine->event_codes_for_ruleset(s_sample_source);
auto rules_event_names = libsinsp::events::event_set_to_names(rules_event_set);
// note: including even one generic event will cause PPME_GENERIC_E to be
// included in the ruleset's event codes. As such, when translating to names,
@@ -164,7 +155,7 @@ TEST(ConfigureInterestingSets, engine_codes_nonsyscalls_set)
expected_names.insert(generic_names.begin(), generic_names.end());
ASSERT_NAMES_EQ(rules_event_names, expected_names);
auto rules_sc_set = engine->sc_codes_for_ruleset(s_sample_source);
auto rules_sc_set = m_engine->sc_codes_for_ruleset(s_sample_source);
auto rules_sc_names = libsinsp::events::sc_set_to_event_names(rules_sc_set);
ASSERT_NAMES_EQ(rules_sc_names, strset_t({
"connect", "accept", "accept4", "umount2", "open", "ptrace", "mmap", "execve", "read",
@@ -172,11 +163,13 @@ TEST(ConfigureInterestingSets, engine_codes_nonsyscalls_set)
}));
}
TEST(ConfigureInterestingSets, selection_not_allevents)
TEST_F(test_falco_engine, selection_not_allevents)
{
load_rules(ruleset_from_filters(s_sample_filters), "dummy_ruleset.yaml");
falco::app::state s2;
// run app action with fake engine and without the `-A` option
s2.engine = mock_engine_from_filters(s_sample_filters);
s2.engine = m_engine;
s2.options.all_events = false;
ASSERT_EQ(s2.options.all_events, false);
@@ -217,11 +210,13 @@ TEST(ConfigureInterestingSets, selection_not_allevents)
ASSERT_EQ(s2.selected_sc_set, union_set);
}
TEST(ConfigureInterestingSets, selection_allevents)
TEST_F(test_falco_engine, selection_allevents)
{
load_rules(ruleset_from_filters(s_sample_filters), "dummy_ruleset.yaml");
falco::app::state s3;
// run app action with fake engine and with the `-A` option
s3.engine = mock_engine_from_filters(s_sample_filters);
s3.engine = m_engine;
s3.options.all_events = true;
auto result = falco::app::actions::configure_interesting_sets(s3);
ASSERT_TRUE(result.success);
@@ -250,14 +245,15 @@ TEST(ConfigureInterestingSets, selection_allevents)
ASSERT_EQ(s3.selected_sc_set, union_set);
}
TEST(ConfigureInterestingSets, selection_generic_evts)
TEST_F(test_falco_engine, selection_generic_evts)
{
falco::app::state s4;
// run app action with fake engine and without the `-A` option
s4.options.all_events = false;
auto filters = s_sample_filters;
filters.insert(s_sample_generic_filters.begin(), s_sample_generic_filters.end());
s4.engine = mock_engine_from_filters(filters);
load_rules(ruleset_from_filters(filters), "dummy_ruleset.yaml");
s4.engine = m_engine;
auto result = falco::app::actions::configure_interesting_sets(s4);
ASSERT_TRUE(result.success);
ASSERT_EQ(result.errstr, "");
@@ -282,12 +278,14 @@ TEST(ConfigureInterestingSets, selection_generic_evts)
// (either default or custom positive set)
// - events in the custom negative set are removed from the selected set
// - if `-A` is not set, events from the IO set are removed from the selected set
TEST(ConfigureInterestingSets, selection_custom_base_set)
TEST_F(test_falco_engine, selection_custom_base_set)
{
load_rules(ruleset_from_filters(s_sample_filters), "dummy_ruleset.yaml");
falco::app::state s5;
// run app action with fake engine and without the `-A` option
s5.options.all_events = true;
s5.engine = mock_engine_from_filters(s_sample_filters);
s5.engine = m_engine;
auto default_base_set = libsinsp::events::sinsp_state_sc_set();
// non-empty custom base set (both positive and negative)
@@ -365,12 +363,14 @@ TEST(ConfigureInterestingSets, selection_custom_base_set)
ASSERT_NAMES_NOCONTAIN(selected_sc_names, unexpected_sc_names);
}
TEST(ConfigureInterestingSets, selection_custom_base_set_repair)
TEST_F(test_falco_engine, selection_custom_base_set_repair)
{
load_rules(ruleset_from_filters(s_sample_filters), "dummy_ruleset.yaml");
falco::app::state s6;
// run app action with fake engine and without the `-A` option
s6.options.all_events = false;
s6.engine = mock_engine_from_filters(s_sample_filters);
s6.engine = m_engine;
// note: here we use file syscalls (e.g. open, openat) and have a custom
// positive set, so we expect syscalls such as "close" to be selected as
@@ -393,12 +393,14 @@ TEST(ConfigureInterestingSets, selection_custom_base_set_repair)
ASSERT_NAMES_NOCONTAIN(selected_sc_names, unexpected_sc_names);
}
TEST(ConfigureInterestingSets, selection_empty_custom_base_set_repair)
TEST_F(test_falco_engine, selection_empty_custom_base_set_repair)
{
load_rules(ruleset_from_filters(s_sample_filters), "dummy_ruleset.yaml");
falco::app::state s7;
// run app action with fake engine and with the `-A` option
s7.options.all_events = true;
s7.engine = mock_engine_from_filters(s_sample_filters);
s7.engine = m_engine;
// simulate empty custom set but repair option set.
s7.config->m_base_syscalls_custom_set = {};

View File

@@ -8,7 +8,7 @@ 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
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

View File

@@ -8,7 +8,7 @@ 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
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
@@ -19,10 +19,10 @@ limitations under the License.
#include "falco_test_var.h"
#ifndef __EMSCRIPTEN__
TEST(ActionLoadConfig, check_engine_config_is_correctly_parsed)
TEST(ActionLoadConfig, check_kmod_engine_config)
{
falco::app::state s = {};
s.options.conf_filename = NEW_ENGINE_CONFIG_CHANGED;
s.options.conf_filename = TEST_ENGINE_KMOD_CONFIG;
EXPECT_ACTION_OK(falco::app::actions::load_config(s));
// Check that the engine is the kmod
@@ -45,105 +45,26 @@ TEST(ActionLoadConfig, check_engine_config_is_correctly_parsed)
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)
TEST(ActionLoadConfig, check_modern_engine_config)
{
falco::app::state s;
s.options.modern_bpf = true;
s.options.conf_filename = NEW_ENGINE_CONFIG_CHANGED;
falco::app::state s = {};
s.options.conf_filename = TEST_ENGINE_MODERN_CONFIG;
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 the engine is the modern ebpf
EXPECT_TRUE(s.config->m_engine_mode == engine_kind_t::MODERN_EBPF);
// 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);
// Check that modern ebpf params are the ones specified in the config
EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_buffer, 1);
EXPECT_EQ(s.config->m_modern_ebpf.m_buf_size_preset, 4);
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_EQ(s.config->m_kmod.m_buf_size_preset, 0);
EXPECT_FALSE(s.config->m_kmod.m_drop_failed_exit);
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);
@@ -152,45 +73,6 @@ TEST(ActionLoadConfig, check_override_command_line_modern)
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

@@ -8,7 +8,7 @@ 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
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

View File

@@ -8,23 +8,23 @@ 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
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 <future>
#include <thread>
#include <vector>
#include <memory>
#include <chrono>
#include <falco/atomic_signal_handler.h>
#include <falco/logger.h>
#include <gtest/gtest.h>
#include <chrono>
#include <future>
#include <memory>
#include <vector>
TEST(AtomicSignalHandler, lock_free_implementation)
{
ASSERT_TRUE(falco::atomic_signal_handler().is_lock_free());
@@ -33,55 +33,50 @@ TEST(AtomicSignalHandler, lock_free_implementation)
TEST(AtomicSignalHandler, handle_once_wait_consistency)
{
constexpr const auto thread_num = 10;
constexpr const auto thread_wait_sec = 2;
constexpr const auto handler_wait_sec = 1;
constexpr const std::chrono::seconds thread_wait_sec{2};
constexpr const std::chrono::seconds handler_wait_sec{1};
// have a shared signal handler
falco::atomic_signal_handler handler;
// launch a bunch of threads all syncing on the same handler
typedef struct
struct task_result_t
{
bool handled;
uint64_t duration_secs;
} task_result_t;
std::chrono::seconds duration_secs;
};
std::vector<std::future<task_result_t>> futures;
std::vector<std::unique_ptr<std::thread>> threads;
for (int i = 0; i < thread_num; i++)
{
std::packaged_task<task_result_t()> task([&handler, &thread_wait_sec]{
auto start = std::chrono::high_resolution_clock::now();
task_result_t res;
res.handled = false;
while (!handler.handled())
{
if (handler.triggered())
futures.emplace_back(std::async(std::launch::async,
[&handler, thread_wait_sec]() {
auto start = std::chrono::high_resolution_clock::now();
task_result_t res;
res.handled = false;
while (!handler.handled())
{
res.handled = handler.handle([&thread_wait_sec]{
std::this_thread::sleep_for (std::chrono::seconds(thread_wait_sec));
});
if (handler.triggered())
{
res.handled = handler.handle([thread_wait_sec]() {
std::this_thread::sleep_for(thread_wait_sec);
});
}
}
}
auto diff = std::chrono::high_resolution_clock::now() - start;
res.duration_secs = std::chrono::duration_cast<std::chrono::seconds>(diff).count();
return res;
});
futures.push_back(task.get_future());
threads.emplace_back();
threads[i].reset(new std::thread(std::move(task)));
auto diff = std::chrono::high_resolution_clock::now() - start;
res.duration_secs = std::chrono::duration_cast<std::chrono::seconds>(diff);
return res;
}));
}
// wait a bit, then trigger the signal handler from the main thread
auto total_handled = 0;
auto start = std::chrono::high_resolution_clock::now();
std::this_thread::sleep_for (std::chrono::seconds(handler_wait_sec));
std::this_thread::sleep_for(handler_wait_sec);
handler.trigger();
for (int i = 0; i < thread_num; i++)
{
// we need to check that all threads didn't quit before
// the handle() function finished executing
futures[i].wait();
threads[i]->join();
// wait for all threads to finish and get the results from the futures
auto res = futures[i].get();
if (res.handled)
{
@@ -92,7 +87,7 @@ TEST(AtomicSignalHandler, handle_once_wait_consistency)
// check that the total time is consistent with the expectations
auto diff = std::chrono::high_resolution_clock::now() - start;
auto secs = std::chrono::duration_cast<std::chrono::seconds>(diff).count();
auto secs = std::chrono::duration_cast<std::chrono::seconds>(diff);
ASSERT_GE(secs, thread_wait_sec + handler_wait_sec);
// check that only one thread handled the signal

View File

@@ -20,16 +20,15 @@
# Falco engine #
################
# Unchanged
engine:
kind: kmod
kmod:
buf_size_preset: 4
buf_size_preset: 2
drop_failed_exit: false
ebpf:
probe: /path/to/probe.o
buf_size_preset: 4
drop_failed_exit: false
buf_size_preset: 7
drop_failed_exit: true
modern_ebpf:
cpus_for_each_buffer: 2
buf_size_preset: 4
@@ -39,15 +38,3 @@ engine:
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

@@ -21,32 +21,20 @@
################
engine:
kind: kmod
kind: modern_ebpf
kmod:
buf_size_preset: 2 # changed default value
drop_failed_exit: false
buf_size_preset: 1
drop_failed_exit: true
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
cpus_for_each_buffer: 1
# missing `buf_size_preset` should be defaulted
drop_failed_exit: true
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

@@ -8,7 +8,7 @@ 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
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
@@ -109,22 +109,518 @@ TEST(Configuration, modify_yaml_fields)
ASSERT_EQ(conf.get_scalar<bool>(key, false), true);
}
TEST(Configuration, configuration_config_files_secondary_fail)
{
/* Test that a secondary config file is not able to include anything, triggering an exception. */
const std::string main_conf_yaml =
yaml_helper::configs_key + ":\n"
" - conf_2.yaml\n"
" - conf_3.yaml\n"
"foo: bar\n"
"base_value:\n"
" id: 1\n"
" name: foo\n";
const std::string conf_yaml_2 =
yaml_helper::configs_key + ":\n"
" - conf_4.yaml\n"
"foo2: bar2\n"
"base_value_2:\n"
" id: 2\n";
std::ofstream outfile("main.yaml");
outfile << main_conf_yaml;
outfile.close();
outfile.open("conf_2.yaml");
outfile << conf_yaml_2;
outfile.close();
std::vector<std::string> cmdline_config_options;
std::vector<std::string> loaded_conf_files;
falco_configuration falco_config;
ASSERT_ANY_THROW(falco_config.init_from_file("main.yaml", loaded_conf_files, cmdline_config_options));
std::filesystem::remove("main.yaml");
std::filesystem::remove("conf_2.yaml");
}
TEST(Configuration, configuration_config_files_ok)
{
/* Test that every included config file was correctly parsed */
const std::string main_conf_yaml =
yaml_helper::configs_key + ":\n"
" - conf_2.yaml\n"
" - conf_3.yaml\n"
"foo: bar\n"
"base_value:\n"
" id: 1\n"
" name: foo\n";
const std::string conf_yaml_2 =
"foo2: bar2\n"
"base_value_2:\n"
" id: 2\n";
const std::string conf_yaml_3 =
"foo3: bar3\n"
"base_value_3:\n"
" id: 3\n"
" name: foo3\n";
const std::string conf_yaml_4 =
"base_value_4:\n"
" id: 4\n";
std::ofstream outfile("main.yaml");
outfile << main_conf_yaml;
outfile.close();
outfile.open("conf_2.yaml");
outfile << conf_yaml_2;
outfile.close();
outfile.open("conf_3.yaml");
outfile << conf_yaml_3;
outfile.close();
outfile.open("conf_4.yaml");
outfile << conf_yaml_4;
outfile.close();
std::vector<std::string> cmdline_config_options;
std::vector<std::string> loaded_conf_files;
falco_configuration falco_config;
ASSERT_NO_THROW(falco_config.init_from_file("main.yaml", loaded_conf_files, cmdline_config_options));
// main + conf_2 + conf_3
ASSERT_EQ(loaded_conf_files.size(), 3);
ASSERT_TRUE(falco_config.config.is_defined("foo"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo", ""), "bar");
ASSERT_TRUE(falco_config.config.is_defined("base_value.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value.id", 0), 1);
ASSERT_TRUE(falco_config.config.is_defined("base_value.name"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("base_value.name", ""), "foo");
ASSERT_TRUE(falco_config.config.is_defined("foo2"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo2", ""), "bar2");
ASSERT_TRUE(falco_config.config.is_defined("base_value_2.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value_2.id", 0), 2);
ASSERT_TRUE(falco_config.config.is_defined("foo3"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo3", ""), "bar3");
ASSERT_TRUE(falco_config.config.is_defined("base_value_3.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value_3.id", 0), 3);
ASSERT_TRUE(falco_config.config.is_defined("base_value_3.name"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("base_value_3.name", ""), "foo3");
ASSERT_FALSE(falco_config.config.is_defined("base_value_4.id")); // conf_4 is not included
std::filesystem::remove("main.yaml");
std::filesystem::remove("conf_2.yaml");
std::filesystem::remove("conf_3.yaml");
std::filesystem::remove("conf_4.yaml");
}
TEST(Configuration, configuration_config_files_relative_main)
{
/*
* Test that relative path are treated as relative to cwd and not to main config folder,
* and that absolute includes are ok too.
*/
const auto temp_main = std::filesystem::temp_directory_path() / "main.yaml";
// So, conf_2 will be looked up in the same folder as main config file,
// while conf_3, since is absolute, will be looked up in the absolute path (and found!).
const std::string main_conf_yaml =
yaml_helper::configs_key + ":\n"
" - conf_2.yaml\n"
" - " +
std::filesystem::current_path().string() + "/conf_3.yaml\n"
"foo: bar\n"
"base_value:\n"
" id: 1\n"
" name: foo\n";
const std::string conf_yaml_2 =
"foo2: bar2\n"
"base_value_2:\n"
" id: 2\n";
const std::string conf_yaml_3 =
"foo3: bar3\n"
"base_value_3:\n"
" id: 3\n"
" name: foo3\n";
std::ofstream outfile(temp_main.string());
outfile << main_conf_yaml;
outfile.close();
outfile.open("conf_2.yaml");
outfile << conf_yaml_2;
outfile.close();
outfile.open("conf_3.yaml");
outfile << conf_yaml_3;
outfile.close();
std::vector<std::string> cmdline_config_options;
std::vector<std::string> loaded_conf_files;
falco_configuration falco_config;
ASSERT_NO_THROW(falco_config.init_from_file(temp_main.string(), loaded_conf_files, cmdline_config_options));
// main + conf_2 + conf_3
ASSERT_EQ(loaded_conf_files.size(), 3);
ASSERT_TRUE(falco_config.config.is_defined("foo"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo", ""), "bar");
ASSERT_TRUE(falco_config.config.is_defined("base_value.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value.id", 0), 1);
ASSERT_TRUE(falco_config.config.is_defined("base_value.name"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("base_value.name", ""), "foo");
ASSERT_TRUE(falco_config.config.is_defined("foo2"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo2", ""), "bar2");
ASSERT_TRUE(falco_config.config.is_defined("base_value_2"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value_2.id", 0), 2);
ASSERT_TRUE(falco_config.config.is_defined("base_value_3.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value_3.id", 0), 3);
std::filesystem::remove(temp_main.string());
std::filesystem::remove("conf_2.yaml");
std::filesystem::remove("conf_3.yaml");
}
TEST(Configuration, configuration_config_files_override)
{
/* Test that included config files are able to override configs from main file */
const std::string main_conf_yaml =
yaml_helper::configs_key + ":\n"
" - conf_2.yaml\n"
" - conf_3.yaml\n"
"foo: bar\n"
"base_value:\n"
" id: 1\n"
" name: foo\n";
const std::string conf_yaml_2 =
"foo2: bar2\n"
"base_value_2:\n"
" id: 2\n";
const std::string conf_yaml_3 =
"base_value:\n"
" id: 3\n";
std::ofstream outfile("main.yaml");
outfile << main_conf_yaml;
outfile.close();
outfile.open("conf_2.yaml");
outfile << conf_yaml_2;
outfile.close();
outfile.open("conf_3.yaml");
outfile << conf_yaml_3;
outfile.close();
std::vector<std::string> cmdline_config_options;
std::vector<std::string> loaded_conf_files;
falco_configuration falco_config;
ASSERT_NO_THROW(falco_config.init_from_file("main.yaml", loaded_conf_files, cmdline_config_options));
// main + conf_2 + conf_3
ASSERT_EQ(loaded_conf_files.size(), 3);
ASSERT_TRUE(falco_config.config.is_defined("foo"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo", ""), "bar");
ASSERT_TRUE(falco_config.config.is_defined("base_value.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value.id", 0), 3); // overridden!
ASSERT_FALSE(falco_config.config.is_defined("base_value.name")); // no more present since entire `base_value` block was overridden
ASSERT_TRUE(falco_config.config.is_defined("foo2"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo2", ""), "bar2");
ASSERT_TRUE(falco_config.config.is_defined("base_value_2.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value_2.id", 0), 2);
ASSERT_FALSE(falco_config.config.is_defined("base_value_3.id")); // not defined
std::filesystem::remove("main.yaml");
std::filesystem::remove("conf_2.yaml");
std::filesystem::remove("conf_3.yaml");
}
TEST(Configuration, configuration_config_files_unexistent)
{
/* Test that including an unexistent file just skips it */
const std::string main_conf_yaml =
yaml_helper::configs_key + ":\n"
" - conf_5.yaml\n"
"base_value:\n"
" id: 1\n"
" name: foo\n";
std::ofstream outfile("main.yaml");
outfile << main_conf_yaml;
outfile.close();
std::vector<std::string> cmdline_config_options;
std::vector<std::string> loaded_conf_files;
falco_configuration falco_config;
ASSERT_NO_THROW(falco_config.init_from_file("main.yaml", loaded_conf_files, cmdline_config_options));
// main
ASSERT_EQ(loaded_conf_files.size(), 1);
ASSERT_TRUE(falco_config.config.is_defined("base_value.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value.id", 0), 1);
ASSERT_TRUE(falco_config.config.is_defined("base_value.name"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("base_value.name", ""), "foo");
std::filesystem::remove("main.yaml");
}
TEST(Configuration, configuration_config_files_scalar_config_files)
{
/* Test that a single file can be included as a scalar (thanks to get_sequence_from_node magic) */
const std::string main_conf_yaml =
yaml_helper::configs_key + ": conf_2.yaml\n"
"foo: bar\n"
"base_value:\n"
" id: 1\n"
" name: foo\n";
const std::string conf_yaml_2 =
"foo2: bar2\n"
"base_value_2:\n"
" id: 2\n";
std::ofstream outfile("main.yaml");
outfile << main_conf_yaml;
outfile.close();
outfile.open("conf_2.yaml");
outfile << conf_yaml_2;
outfile.close();
std::vector<std::string> cmdline_config_options;
std::vector<std::string> loaded_conf_files;
falco_configuration falco_config;
ASSERT_NO_THROW(falco_config.init_from_file("main.yaml", loaded_conf_files, cmdline_config_options));
// main + conf_2
ASSERT_EQ(loaded_conf_files.size(), 2);
ASSERT_TRUE(falco_config.config.is_defined("foo"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo", ""), "bar");
ASSERT_TRUE(falco_config.config.is_defined("base_value.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value.id", 0), 1);
ASSERT_TRUE(falco_config.config.is_defined("base_value.name"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("base_value.name", ""), "foo");
ASSERT_TRUE(falco_config.config.is_defined("foo2"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo2", ""), "bar2");
ASSERT_TRUE(falco_config.config.is_defined("base_value_2.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value_2.id", 0), 2);
std::filesystem::remove("main.yaml");
std::filesystem::remove("conf_2.yaml");
}
TEST(Configuration, configuration_config_files_empty_config_files)
{
/* Test that empty includes list is accepted */
const std::string main_conf_yaml =
yaml_helper::configs_key + ":\n"
"foo: bar\n"
"base_value:\n"
" id: 1\n"
" name: foo\n";
std::ofstream outfile("main.yaml");
outfile << main_conf_yaml;
outfile.close();
std::vector<std::string> cmdline_config_options;
std::vector<std::string> loaded_conf_files;
falco_configuration falco_config;
ASSERT_NO_THROW(falco_config.init_from_file("main.yaml", loaded_conf_files, cmdline_config_options));
// main
ASSERT_EQ(loaded_conf_files.size(), 1);
ASSERT_TRUE(falco_config.config.is_defined("foo"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo", ""), "bar");
ASSERT_TRUE(falco_config.config.is_defined("base_value.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value.id", 0), 1);
ASSERT_TRUE(falco_config.config.is_defined("base_value.name"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("base_value.name", ""), "foo");
std::filesystem::remove("main.yaml");
}
TEST(Configuration, configuration_config_files_self)
{
/* Test that main config file cannot include itself */
const std::string main_conf_yaml =
yaml_helper::configs_key + ": main.yaml\n"
"foo: bar\n"
"base_value:\n"
" id: 1\n"
" name: foo\n";
std::ofstream outfile("main.yaml");
outfile << main_conf_yaml;
outfile.close();
std::vector<std::string> cmdline_config_options;
std::vector<std::string> loaded_conf_files;
falco_configuration falco_config;
ASSERT_ANY_THROW(falco_config.init_from_file("main.yaml", loaded_conf_files, cmdline_config_options));
std::filesystem::remove("main.yaml");
}
TEST(Configuration, configuration_config_files_directory)
{
/*
* Test that when main config file includes a config directory,
* the config directory is parsed in lexicographic order,
* and only regular files are parsed.
*/
// Main config includes whole temp directory
const std::string main_conf_yaml =
yaml_helper::configs_key + ": " + std::filesystem::temp_directory_path().string() + "/test\n"
"foo: bar\n"
"base_value:\n"
" id: 1\n"
" name: foo\n";
const std::string conf_yaml_2 =
"foo2: bar2\n"
"base_value_2:\n"
" id: 2\n";
const std::string conf_yaml_3 =
"foo2: bar3\n"
"base_value_3:\n"
" id: 3\n"
" name: foo3\n";
const std::string conf_yaml_4 =
"foo4: bar4\n";
std::filesystem::create_directory(std::filesystem::temp_directory_path() / "test");
std::ofstream outfile("main.yaml");
outfile << main_conf_yaml;
outfile.close();
outfile.open(std::filesystem::temp_directory_path()/"test/conf_2.yaml");
outfile << conf_yaml_2;
outfile.close();
outfile.open(std::filesystem::temp_directory_path()/"test/conf_3.yaml");
outfile << conf_yaml_3;
outfile.close();
// Create a directory and create a config inside it. We will later check that it was not parsed
std::filesystem::create_directory(std::filesystem::temp_directory_path() / "test" / "foo");
outfile.open(std::filesystem::temp_directory_path()/"test/foo/conf_4.yaml");
outfile << conf_yaml_4;
outfile.close();
std::vector<std::string> cmdline_config_options;
std::vector<std::string> loaded_conf_files;
falco_configuration falco_config;
ASSERT_NO_THROW(falco_config.init_from_file("main.yaml", loaded_conf_files, cmdline_config_options));
// main + conf_2 + conf_3.
// test/foo is not parsed.
ASSERT_EQ(loaded_conf_files.size(), 3);
ASSERT_TRUE(falco_config.config.is_defined("foo"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo", ""), "bar");
ASSERT_TRUE(falco_config.config.is_defined("base_value.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value.id", 0), 1);
ASSERT_TRUE(falco_config.config.is_defined("base_value.name"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("base_value.name", ""), "foo");
ASSERT_TRUE(falco_config.config.is_defined("base_value_2"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value_2.id", 0), 2);
ASSERT_TRUE(falco_config.config.is_defined("base_value_3.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value_3.id", 0), 3);
ASSERT_TRUE(falco_config.config.is_defined("foo2"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo2", ""), "bar3");
ASSERT_FALSE(falco_config.config.is_defined("foo4"));
std::filesystem::remove("main");
std::filesystem::remove_all(std::filesystem::temp_directory_path()/"test");
}
TEST(Configuration, configuration_config_files_cmdline)
{
/* Test that we support including configs files from cmdline option */
const std::string main_conf_yaml =
"foo: bar\n"
"base_value:\n"
" id: 1\n"
" name: foo\n";
const std::string conf_yaml_2 =
"foo2: bar2\n"
"base_value_2:\n"
" id: 2\n";
std::ofstream outfile("main.yaml");
outfile << main_conf_yaml;
outfile.close();
outfile.open("conf_2.yaml");
outfile << conf_yaml_2;
outfile.close();
// Pass "config_files=..." cmdline option
std::vector<std::string> cmdline_config_options;
cmdline_config_options.push_back((yaml_helper::configs_key+"=conf_2.yaml"));
std::vector<std::string> loaded_conf_files;
falco_configuration falco_config;
ASSERT_NO_THROW(falco_config.init_from_file("main.yaml", loaded_conf_files, cmdline_config_options));
// main + conf_2
ASSERT_EQ(loaded_conf_files.size(), 2);
ASSERT_TRUE(falco_config.config.is_defined("foo"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo", ""), "bar");
ASSERT_TRUE(falco_config.config.is_defined("base_value.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value.id", 0), 1);
ASSERT_TRUE(falco_config.config.is_defined("base_value.name"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("base_value.name", ""), "foo");
ASSERT_TRUE(falco_config.config.is_defined("foo2"));
ASSERT_EQ(falco_config.config.get_scalar<std::string>("foo2", ""), "bar2");
ASSERT_TRUE(falco_config.config.is_defined("base_value_2.id"));
ASSERT_EQ(falco_config.config.get_scalar<int>("base_value_2.id", 0), 2);
std::filesystem::remove("main.yaml");
std::filesystem::remove("conf_2.yaml");
}
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";
SET_ENV_VAR(env_var_name.c_str(), env_var_value.c_str());
yaml_helper conf;
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"
@@ -133,52 +629,135 @@ 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 */
SET_ENV_VAR(env_var_name.c_str(), env_var_value.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)
@@ -220,9 +799,9 @@ TEST(Configuration, configuration_webserver_ip)
std::vector<std::string> cmdline_config_options;
cmdline_config_options.push_back(option);
EXPECT_NO_THROW(falco_config.init(cmdline_config_options));
EXPECT_NO_THROW(falco_config.init_from_content("", cmdline_config_options));
ASSERT_EQ(falco_config.m_webserver_listen_address, address);
ASSERT_EQ(falco_config.m_webserver_config.m_listen_address, address);
}
std::vector<std::string> invalid_addresses = {"327.0.0.1",
@@ -257,6 +836,6 @@ TEST(Configuration, configuration_webserver_ip)
std::vector<std::string> cmdline_config_options;
cmdline_config_options.push_back(option);
EXPECT_ANY_THROW(falco_config.init(cmdline_config_options));
EXPECT_ANY_THROW(falco_config.init_from_content("", cmdline_config_options));
}
}

View File

@@ -0,0 +1,60 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright (C) 2024 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/configuration.h>
TEST(ConfigurationRuleSelection, parse_yaml)
{
falco_configuration falco_config;
EXPECT_NO_THROW(falco_config.init_from_content(R"(
rules:
- enable:
rule: 'Terminal Shell in Container'
- disable:
tag: experimental
- enable:
rule: 'hello*'
)", {}));
ASSERT_EQ(falco_config.m_rules_selection.size(), 3);
ASSERT_EQ(falco_config.m_rules_selection[0].m_op, falco_configuration::rule_selection_operation::enable);
ASSERT_EQ(falco_config.m_rules_selection[0].m_rule, "Terminal Shell in Container");
ASSERT_EQ(falco_config.m_rules_selection[1].m_op, falco_configuration::rule_selection_operation::disable);
ASSERT_EQ(falco_config.m_rules_selection[1].m_tag, "experimental");
ASSERT_EQ(falco_config.m_rules_selection[2].m_op, falco_configuration::rule_selection_operation::enable);
ASSERT_EQ(falco_config.m_rules_selection[2].m_rule, "hello*");
}
TEST(ConfigurationRuleSelection, cli_options)
{
falco_configuration falco_config;
EXPECT_NO_THROW(falco_config.init_from_content("", std::vector<std::string>{"rules[].disable.tag=maturity_incubating", "rules[].enable.rule=Adding ssh keys to authorized_keys"}));
ASSERT_EQ(falco_config.m_rules_selection.size(), 2);
ASSERT_EQ(falco_config.m_rules_selection[0].m_op, falco_configuration::rule_selection_operation::disable);
ASSERT_EQ(falco_config.m_rules_selection[0].m_tag, "maturity_incubating");
ASSERT_EQ(falco_config.m_rules_selection[1].m_op, falco_configuration::rule_selection_operation::enable);
ASSERT_EQ(falco_config.m_rules_selection[1].m_rule, "Adding ssh keys to authorized_keys");
}

View File

@@ -1,4 +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"
#define TEST_ENGINE_KMOD_CONFIG "${CMAKE_SOURCE_DIR}/unit_tests/falco/test_configs/engine_kmod_config.yaml"
#define TEST_ENGINE_MODERN_CONFIG "${CMAKE_SOURCE_DIR}/unit_tests/falco/test_configs/engine_modern_config.yaml"

View File

@@ -0,0 +1,87 @@
#include "test_falco_engine.h"
test_falco_engine::test_falco_engine()
{
// create a falco engine ready to load the ruleset
m_filter_factory = std::make_shared<sinsp_filter_factory>(&m_inspector, m_filterlist);
m_formatter_factory = std::make_shared<sinsp_evt_formatter_factory>(&m_inspector, m_filterlist);
m_engine = std::make_shared<falco_engine>();
m_engine->add_source(m_sample_source, m_filter_factory, m_formatter_factory);
}
bool test_falco_engine::load_rules(const std::string& rules_content, const 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 test_falco_engine::num_rules_for_ruleset(const std::string& ruleset)
{
return m_engine->num_rules_for_ruleset(ruleset);
}
bool test_falco_engine::has_warnings() const
{
return m_load_result->has_warnings();
}
bool test_falco_engine::check_warning_message(const std::string& warning_msg) const
{
if(!m_load_result->has_warnings())
{
return false;
}
for(const 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 test_falco_engine::check_error_message(const std::string& error_msg) const
{
// if the loading is successful there are no errors
if(m_load_result->successful())
{
return false;
}
for(const 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 test_falco_engine::get_compiled_rule_condition(std::string rule_name) const
{
auto rule_description = m_engine->describe_rule(&rule_name, {});
return rule_description["rules"][0]["details"]["condition_compiled"].template get<std::string>();
}

View File

@@ -0,0 +1,33 @@
#pragma once
#include "falco_engine.h"
#include "rule_loader_reader.h"
#include "rule_loader_compiler.h"
#include "rule_loading_messages.h"
#include <gtest/gtest.h>
class test_falco_engine : public testing::Test
{
protected:
test_falco_engine();
bool load_rules(const std::string& rules_content, const std::string& rules_filename);
// This must be kept in line with the (private) falco_engine::s_default_ruleset
uint64_t num_rules_for_ruleset(const std::string& ruleset = "falco-default-ruleset");
bool has_warnings() const;
bool check_warning_message(const std::string& warning_msg) const;
bool check_error_message(const std::string& error_msg) const;
std::string get_compiled_rule_condition(std::string rule_name = "") const;
std::string m_sample_ruleset = "sample-ruleset";
std::string m_sample_source = falco_common::syscall_source;
sinsp m_inspector;
sinsp_filter_check_list m_filterlist;
std::shared_ptr<sinsp_filter_factory> m_filter_factory;
std::shared_ptr<sinsp_evt_formatter_factory> m_formatter_factory;
std::shared_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;
};

View File

@@ -11,11 +11,12 @@
# "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
filter_ruleset.cpp
evttype_index_ruleset.cpp
formats.cpp
filter_details_resolver.cpp
@@ -25,24 +26,22 @@ 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")
endif()
add_dependencies(falco_engine yamlcpp njson)
target_include_directories(falco_engine
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${TBB_INCLUDE_DIR}
)
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")
target_link_libraries(falco_engine "${FALCO_SINSP_LIBRARY}" "${YAMLCPP_LIB}")
target_link_libraries(falco_engine
PUBLIC
sinsp
nlohmann_json::nlohmann_json
yaml-cpp
)

View File

@@ -17,10 +17,14 @@ limitations under the License.
#include "evttype_index_ruleset.h"
#include "falco_utils.h"
#include "../falco/logger.h"
#include <algorithm>
evttype_index_ruleset::evttype_index_ruleset(
std::shared_ptr<gen_event_filter_factory> f): m_filter_factory(f)
std::shared_ptr<sinsp_filter_factory> f): m_filter_factory(f)
{
}
@@ -111,11 +115,11 @@ uint64_t evttype_index_ruleset::ruleset_filters::num_filters()
return m_filters.size();
}
bool evttype_index_ruleset::ruleset_filters::run(gen_event *evt, falco_rule& match)
bool evttype_index_ruleset::ruleset_filters::run(sinsp_evt *evt, falco_rule& match)
{
if(evt->get_type() < m_filter_by_event_type.size())
{
for(auto &wrap : m_filter_by_event_type[evt->get_type()])
for(const auto &wrap : m_filter_by_event_type[evt->get_type()])
{
if(wrap->filter->run(evt))
{
@@ -126,7 +130,7 @@ bool evttype_index_ruleset::ruleset_filters::run(gen_event *evt, falco_rule& mat
}
// Finally, try filters that are not specific to an event type.
for(auto &wrap : m_filter_all_event_types)
for(const auto &wrap : m_filter_all_event_types)
{
if(wrap->filter->run(evt))
{
@@ -138,13 +142,13 @@ bool evttype_index_ruleset::ruleset_filters::run(gen_event *evt, falco_rule& mat
return false;
}
bool evttype_index_ruleset::ruleset_filters::run(gen_event *evt, std::vector<falco_rule>& matches)
bool evttype_index_ruleset::ruleset_filters::run(sinsp_evt *evt, std::vector<falco_rule>& matches)
{
bool match_found = false;
if(evt->get_type() < m_filter_by_event_type.size())
{
for(auto &wrap : m_filter_by_event_type[evt->get_type()])
for(const auto &wrap : m_filter_by_event_type[evt->get_type()])
{
if(wrap->filter->run(evt))
{
@@ -160,7 +164,7 @@ bool evttype_index_ruleset::ruleset_filters::run(gen_event *evt, std::vector<fal
}
// Finally, try filters that are not specific to an event type.
for(auto &wrap : m_filter_all_event_types)
for(const auto &wrap : m_filter_all_event_types)
{
if(wrap->filter->run(evt))
{
@@ -175,7 +179,7 @@ bool evttype_index_ruleset::ruleset_filters::run(gen_event *evt, std::vector<fal
libsinsp::events::set<ppm_sc_code> evttype_index_ruleset::ruleset_filters::sc_codes()
{
libsinsp::events::set<ppm_sc_code> res;
for(auto &wrap : m_filters)
for(const auto &wrap : m_filters)
{
res.insert(wrap->sc_codes.begin(), wrap->sc_codes.end());
}
@@ -185,7 +189,7 @@ libsinsp::events::set<ppm_sc_code> evttype_index_ruleset::ruleset_filters::sc_co
libsinsp::events::set<ppm_event_code> evttype_index_ruleset::ruleset_filters::event_codes()
{
libsinsp::events::set<ppm_event_code> res;
for(auto &wrap : m_filters)
for(const auto &wrap : m_filters)
{
res.insert(wrap->event_codes.begin(), wrap->event_codes.end());
}
@@ -194,12 +198,12 @@ libsinsp::events::set<ppm_event_code> evttype_index_ruleset::ruleset_filters::ev
void evttype_index_ruleset::add(
const falco_rule& rule,
std::shared_ptr<gen_event_filter> filter,
std::shared_ptr<sinsp_filter> filter,
std::shared_ptr<libsinsp::filter::ast::expr> condition)
{
try
{
std::shared_ptr<filter_wrapper> wrap(new filter_wrapper());
auto wrap = std::make_shared<filter_wrapper>();
wrap->rule = rule;
wrap->filter = filter;
if(rule.source == falco_common::syscall_source)
@@ -223,50 +227,75 @@ void evttype_index_ruleset::add(
void evttype_index_ruleset::on_loading_complete()
{
// nothing to do for now
print_enabled_rules_falco_logger();
}
void evttype_index_ruleset::print_enabled_rules_falco_logger()
{
falco_logger::log(falco_logger::level::DEBUG, "Enabled rules:\n");
int n = 0;
for (const auto& ruleset_ptr : m_rulesets)
{
if (ruleset_ptr)
{
for (const auto& wrap : ruleset_ptr->get_filters())
{
n++;
falco_logger::log(falco_logger::level::DEBUG, std::string(" ") + wrap->rule.name + "\n");
}
}
}
falco_logger::log(falco_logger::level::DEBUG, "(" + std::to_string(n) + ") enabled rules in total\n");
}
void evttype_index_ruleset::clear()
{
for (size_t i = 0; i < m_rulesets.size(); i++)
{
std::shared_ptr<ruleset_filters> r(new ruleset_filters());
m_rulesets[i] = r;
m_rulesets[i] = std::make_shared<ruleset_filters>();
}
m_filters.clear();
}
void evttype_index_ruleset::enable(const std::string &substring, bool match_exact, uint16_t ruleset_id)
void evttype_index_ruleset::enable(const std::string &pattern, match_type match, uint16_t ruleset_id)
{
enable_disable(substring, match_exact, true, ruleset_id);
enable_disable(pattern, match, true, ruleset_id);
}
void evttype_index_ruleset::disable(const std::string &substring, bool match_exact, uint16_t ruleset_id)
void evttype_index_ruleset::disable(const std::string &pattern, match_type match, uint16_t ruleset_id)
{
enable_disable(substring, match_exact, false, ruleset_id);
enable_disable(pattern, match, false, ruleset_id);
}
void evttype_index_ruleset::enable_disable(const std::string &substring, bool match_exact, bool enabled, uint16_t ruleset_id)
void evttype_index_ruleset::enable_disable(const std::string &pattern, match_type match, bool enabled, uint16_t ruleset_id)
{
while(m_rulesets.size() < (size_t)ruleset_id + 1)
{
m_rulesets.emplace_back(new ruleset_filters());
m_rulesets.emplace_back(std::make_shared<ruleset_filters>());
}
for(const auto &wrap : m_filters)
{
bool matches;
std::string::size_type pos;
if(match_exact)
switch(match)
{
size_t pos = wrap->rule.name.find(substring);
case match_type::exact:
pos = wrap->rule.name.find(pattern);
matches = (substring == "" || (pos == 0 &&
substring.size() == wrap->rule.name.size()));
}
else
{
matches = (substring == "" || (wrap->rule.name.find(substring) != std::string::npos));
matches = (pattern == "" || (pos == 0 &&
pattern.size() == wrap->rule.name.size()));
break;
case match_type::substring:
matches = (pattern == "" || (wrap->rule.name.find(pattern) != std::string::npos));
break;
case match_type::wildcard:
matches = falco::utils::matches_wildcard(pattern, wrap->rule.name);
break;
default:
// should never happen
matches = false;
}
if(matches)
@@ -297,7 +326,7 @@ void evttype_index_ruleset::enable_disable_tags(const std::set<std::string> &tag
{
while(m_rulesets.size() < (size_t)ruleset_id + 1)
{
m_rulesets.emplace_back(new ruleset_filters());
m_rulesets.emplace_back(std::make_shared<ruleset_filters>());
}
for(const auto &wrap : m_filters)
@@ -326,13 +355,13 @@ uint64_t evttype_index_ruleset::enabled_count(uint16_t ruleset_id)
{
while(m_rulesets.size() < (size_t)ruleset_id + 1)
{
m_rulesets.emplace_back(new ruleset_filters());
m_rulesets.emplace_back(std::make_shared<ruleset_filters>());
}
return m_rulesets[ruleset_id]->num_filters();
}
bool evttype_index_ruleset::run(gen_event *evt, falco_rule& match, uint16_t ruleset_id)
bool evttype_index_ruleset::run(sinsp_evt *evt, falco_rule& match, uint16_t ruleset_id)
{
if(m_rulesets.size() < (size_t)ruleset_id + 1)
{
@@ -342,7 +371,7 @@ bool evttype_index_ruleset::run(gen_event *evt, falco_rule& match, uint16_t rule
return m_rulesets[ruleset_id]->run(evt, match);
}
bool evttype_index_ruleset::run(gen_event *evt, std::vector<falco_rule>& matches, uint16_t ruleset_id)
bool evttype_index_ruleset::run(sinsp_evt *evt, std::vector<falco_rule>& matches, uint16_t ruleset_id)
{
if(m_rulesets.size() < (size_t)ruleset_id + 1)
{
@@ -369,7 +398,7 @@ libsinsp::events::set<ppm_sc_code> evttype_index_ruleset::enabled_sc_codes(uint1
}
return m_rulesets[ruleset]->sc_codes();
}
libsinsp::events::set<ppm_event_code> evttype_index_ruleset::enabled_event_codes(uint16_t ruleset)
{
if(m_rulesets.size() < (size_t)ruleset + 1)

View File

@@ -24,11 +24,9 @@ limitations under the License.
#include <map>
#include "filter_ruleset.h"
#include "sinsp.h"
#include "filter.h"
#include "event.h"
#include "gen_filter.h"
#include <libsinsp/sinsp.h>
#include <libsinsp/filter.h>
#include <libsinsp/event.h>
/*!
\brief A filter_ruleset that indexes enabled rules by event type,
@@ -37,31 +35,35 @@ limitations under the License.
class evttype_index_ruleset: public filter_ruleset
{
public:
evttype_index_ruleset(std::shared_ptr<gen_event_filter_factory> factory);
explicit evttype_index_ruleset(std::shared_ptr<sinsp_filter_factory> factory);
virtual ~evttype_index_ruleset();
void add(
const falco_rule& rule,
std::shared_ptr<gen_event_filter> filter,
std::shared_ptr<sinsp_filter> filter,
std::shared_ptr<libsinsp::filter::ast::expr> condition) override;
void clear() override;
bool run(gen_event *evt, falco_rule& match, uint16_t ruleset_id) override;
bool run(gen_event *evt, std::vector<falco_rule>&matches, uint16_t ruleset_id) override;
bool run(sinsp_evt *evt, falco_rule& match, uint16_t ruleset_id) override;
bool run(sinsp_evt *evt, std::vector<falco_rule>&matches, uint16_t ruleset_id) override;
uint64_t enabled_count(uint16_t ruleset_id) override;
void on_loading_complete() override;
// Print each enabled rule when running Falco with falco logger
// log_level=debug; invoked within on_loading_complete()
void print_enabled_rules_falco_logger();
void enable(
const std::string &substring,
bool match_exact,
const std::string &pattern,
match_type match,
uint16_t rulset_id) override;
void disable(
const std::string &substring,
bool match_exact,
const std::string &pattern,
match_type match,
uint16_t rulset_id) override;
void enable_tags(
@@ -87,8 +89,8 @@ private:
// Helper used by enable()/disable()
void enable_disable(
const std::string &substring,
bool match_exact,
const std::string &pattern,
match_type match,
bool enabled,
uint16_t rulset_id);
@@ -103,7 +105,7 @@ private:
falco_rule rule;
libsinsp::events::set<ppm_sc_code> sc_codes;
libsinsp::events::set<ppm_event_code> event_codes;
std::shared_ptr<gen_event_filter> filter;
std::shared_ptr<sinsp_filter> filter;
};
typedef std::list<std::shared_ptr<filter_wrapper>> filter_wrapper_list;
@@ -120,13 +122,18 @@ private:
uint64_t num_filters();
inline const std::set<std::shared_ptr<filter_wrapper>>& get_filters() const
{
return m_filters;
}
// Evaluate an event against the ruleset and return the first rule
// that matched.
bool run(gen_event *evt, falco_rule& match);
bool run(sinsp_evt *evt, falco_rule& match);
// Evaluate an event against the ruleset and return all the
// matching rules.
bool run(gen_event *evt, std::vector<falco_rule>& matches);
// Evaluate an event against the ruleset and return all the
// matching rules.
bool run(sinsp_evt *evt, std::vector<falco_rule>& matches);
libsinsp::events::set<ppm_sc_code> sc_codes();
@@ -153,24 +160,22 @@ private:
// All filters added. The set of enabled filters is held in m_rulesets
std::set<std::shared_ptr<filter_wrapper>> m_filters;
std::shared_ptr<gen_event_filter_factory> m_filter_factory;
std::shared_ptr<sinsp_filter_factory> m_filter_factory;
std::vector<std::string> m_ruleset_names;
};
class evttype_index_ruleset_factory: public filter_ruleset_factory
{
public:
inline evttype_index_ruleset_factory(
std::shared_ptr<gen_event_filter_factory> factory
inline explicit evttype_index_ruleset_factory(
std::shared_ptr<sinsp_filter_factory> factory
): m_filter_factory(factory) { }
inline std::shared_ptr<filter_ruleset> new_ruleset() override
{
std::shared_ptr<filter_ruleset> ret(
new evttype_index_ruleset(m_filter_factory));
return ret;
return std::make_shared<evttype_index_ruleset>(m_filter_factory);
}
private:
std::shared_ptr<gen_event_filter_factory> m_filter_factory;
std::shared_ptr<sinsp_filter_factory> m_filter_factory;
};

View File

@@ -33,7 +33,7 @@ static std::vector<std::string> rule_matching_names = {
"all"
};
bool falco_common::parse_priority(std::string v, priority_type& out)
bool falco_common::parse_priority(const std::string& v, priority_type& out)
{
for (size_t i = 0; i < priority_names.size(); i++)
{
@@ -50,7 +50,7 @@ bool falco_common::parse_priority(std::string v, priority_type& out)
return false;
}
falco_common::priority_type falco_common::parse_priority(std::string v)
falco_common::priority_type falco_common::parse_priority(const std::string& v)
{
falco_common::priority_type out;
if (!parse_priority(v, out))
@@ -87,7 +87,7 @@ std::string falco_common::format_priority(priority_type v, bool shortfmt)
return out;
}
bool falco_common::parse_rule_matching(std::string v, rule_matching& out)
bool falco_common::parse_rule_matching(const std::string& v, rule_matching& out)
{
for (size_t i = 0; i < rule_matching_names.size(); i++)
{

View File

@@ -20,7 +20,7 @@ limitations under the License.
#include <string>
#include <exception>
#include <mutex>
#include <sinsp.h>
#include <libsinsp/sinsp.h>
//
// equivalent to an "unbounded queue" in TBB terms or largest long value
@@ -28,33 +28,17 @@ limitations under the License.
//
#define DEFAULT_OUTPUTS_QUEUE_CAPACITY_UNBOUNDED_MAX_LONG_VALUE std::ptrdiff_t(~size_t(0) / 2)
#define DEFAULT_FALCO_LIBS_THREAD_TABLE_SIZE 262144
//
// Most falco_* classes can throw exceptions. Unless directly related
// to low-level failures like inability to open file, etc, they will
// be of this type.
//
struct falco_exception : std::exception
struct falco_exception : std::runtime_error
{
falco_exception()
{
}
virtual ~falco_exception() throw()
{
}
falco_exception(std::string error_str)
{
m_error_str = error_str;
}
char const* what() const throw()
{
return m_error_str.c_str();
}
std::string m_error_str;
using std::runtime_error::runtime_error;
};
namespace falco_common
@@ -75,8 +59,8 @@ namespace falco_common
PRIORITY_DEBUG = 7
};
bool parse_priority(std::string v, priority_type& out);
priority_type parse_priority(std::string v);
bool parse_priority(const std::string& v, priority_type& out);
priority_type parse_priority(const std::string& v);
bool format_priority(priority_type v, std::string& out, bool shortfmt=false);
std::string format_priority(priority_type v, bool shortfmt=false);
@@ -86,5 +70,5 @@ namespace falco_common
ALL = 1
};
bool parse_rule_matching(std::string v, rule_matching& out);
bool parse_rule_matching(const std::string& v, rule_matching& out);
};

View File

@@ -27,23 +27,22 @@ limitations under the License.
#include <string>
#include <fstream>
#include <functional>
#include <memory>
#include <utility>
#include <vector>
#include <nlohmann/json.hpp>
#include <sinsp.h>
#include <plugin.h>
#include <libsinsp/sinsp.h>
#include <libsinsp/plugin.h>
#include <libsinsp/utils.h>
#include "falco_engine.h"
#include "falco_utils.h"
#include "falco_engine_version.h"
#include "rule_loader_reader.h"
#include "rule_loader_compiler.h"
#include "formats.h"
#include "utils.h"
#include "evttype_index_ruleset.h"
const std::string falco_engine::s_default_ruleset = "falco-default-ruleset";
@@ -53,6 +52,9 @@ using namespace falco;
falco_engine::falco_engine(bool seed_rng)
: m_syscall_source(NULL),
m_syscall_source_idx(SIZE_MAX),
m_rule_reader(std::make_shared<rule_loader::reader>()),
m_rule_collector(std::make_shared<rule_loader::collector>()),
m_rule_compiler(std::make_shared<rule_loader::compiler>()),
m_next_ruleset_id(0),
m_min_priority(falco_common::PRIORITY_DEBUG),
m_sampling_ratio(1), m_sampling_multiplier(0),
@@ -64,12 +66,14 @@ falco_engine::falco_engine(bool seed_rng)
}
m_default_ruleset_id = find_ruleset_id(s_default_ruleset);
fill_engine_state_funcs(m_engine_state);
}
falco_engine::~falco_engine()
{
m_rules.clear();
m_rule_collector.clear();
m_rule_collector->clear();
m_rule_stats_manager.clear();
m_sources.clear();
}
@@ -79,34 +83,44 @@ sinsp_version falco_engine::engine_version()
return sinsp_version(FALCO_ENGINE_VERSION);
}
const falco_source* falco_engine::find_source(const std::string& name) const
void falco_engine::set_rule_reader(std::shared_ptr<rule_loader::reader> reader)
{
auto ret = m_sources.at(name);
if(!ret)
{
throw falco_exception("Unknown event source " + name);
}
return ret;
m_rule_reader = reader;
}
const falco_source* falco_engine::find_source(std::size_t index) const
std::shared_ptr<rule_loader::reader> falco_engine::get_rule_reader()
{
auto ret = m_sources.at(index);
if(!ret)
{
throw falco_exception("Unknown event source index " + std::to_string(index));
}
return ret;
return m_rule_reader;
}
void falco_engine::set_rule_collector(std::shared_ptr<rule_loader::collector> collector)
{
m_rule_collector = collector;
}
std::shared_ptr<rule_loader::collector> falco_engine::get_rule_collector()
{
return m_rule_collector;
}
void falco_engine::set_rule_compiler(std::shared_ptr<rule_loader::compiler> compiler)
{
m_rule_compiler = compiler;
}
std::shared_ptr<rule_loader::compiler> falco_engine::get_rule_compiler()
{
return m_rule_compiler;
}
// Return a key that uniquely represents a field class.
// For now, we assume name + shortdesc is unique.
static std::string fieldclass_key(const gen_event_filter_factory::filter_fieldclass_info &fld_info)
static std::string fieldclass_key(const sinsp_filter_factory::filter_fieldclass_info &fld_info)
{
return fld_info.name + fld_info.shortdesc;
}
void falco_engine::list_fields(std::string &source, bool verbose, bool names_only, bool markdown) const
void falco_engine::list_fields(const std::string &source, bool verbose, bool names_only, bool markdown) const
{
// Maps from field class name + short desc to list of event
// sources for which this field class can be used.
@@ -177,15 +191,6 @@ 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);
@@ -193,54 +198,55 @@ std::unique_ptr<load_result> falco_engine::load_rules(const std::string &rules_c
cfg.replace_output_container_info = m_replace_container_info;
// read rules YAML file and collect its definitions
rule_loader::reader reader;
if (reader.read(cfg, m_rule_collector))
{
if(m_rule_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());
m_last_compile_output = m_rule_compiler->new_compile_output();
m_rule_compiler->compile(cfg, *m_rule_collector, *m_last_compile_output);
// clear the rules known by the engine and each ruleset
m_rules.clear();
for (auto &src : m_sources)
// add rules to each ruleset
{
src.ruleset = src.ruleset_factory->new_ruleset();
src.ruleset = create_ruleset(src.ruleset_factory);
src.ruleset->add_compile_output(*m_last_compile_output,
m_min_priority,
src.name);
}
// 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);
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);
if (rule_id != rule.id)
{
throw falco_exception("Incompatible ID for rule: " + rule.name +
" | compiled ID: " + std::to_string(rule.id) +
" | stats_mgr ID: " + std::to_string(rule_id));
}
// By default rules are enabled/disabled for the default ruleset
// skip the rule if below the minimum priority
if (rule.priority > m_min_priority)
{
continue;
}
if(info->enabled)
{
source->ruleset->enable(rule.name, true, m_default_ruleset_id);
source->ruleset->enable(rule.name, filter_ruleset::match_type::exact, m_default_ruleset_id);
}
else
{
source->ruleset->disable(rule.name, true, m_default_ruleset_id);
source->ruleset->disable(rule.name, filter_ruleset::match_type::exact, m_default_ruleset_id);
}
}
}
@@ -257,58 +263,24 @@ 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);
bool match_exact = false;
enable_rule(substring, enabled, ruleset_id);
}
void falco_engine::enable_rule(const std::string &substring, bool enabled, const uint16_t ruleset_id)
{
for(const auto &it : m_sources)
{
if(enabled)
{
it.ruleset->enable(substring, match_exact, ruleset_id);
it.ruleset->enable(substring, filter_ruleset::match_type::substring, ruleset_id);
}
else
{
it.ruleset->disable(substring, match_exact, ruleset_id);
it.ruleset->disable(substring, filter_ruleset::match_type::substring, ruleset_id);
}
}
}
@@ -316,17 +288,43 @@ 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);
bool match_exact = true;
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)
{
for(const auto &it : m_sources)
{
if(enabled)
{
it.ruleset->enable(rule_name, match_exact, ruleset_id);
it.ruleset->enable(rule_name, filter_ruleset::match_type::exact, ruleset_id);
}
else
{
it.ruleset->disable(rule_name, match_exact, ruleset_id);
it.ruleset->disable(rule_name, filter_ruleset::match_type::exact, ruleset_id);
}
}
}
void falco_engine::enable_rule_wildcard(const std::string &rule_name, bool enabled, const std::string &ruleset)
{
uint16_t ruleset_id = find_ruleset_id(ruleset);
enable_rule_wildcard(rule_name, enabled, ruleset_id);
}
void falco_engine::enable_rule_wildcard(const std::string &rule_name, bool enabled, const uint16_t ruleset_id)
{
for(const auto &it : m_sources)
{
if(enabled)
{
it.ruleset->enable(rule_name, filter_ruleset::match_type::wildcard, ruleset_id);
}
else
{
it.ruleset->disable(rule_name, filter_ruleset::match_type::wildcard, ruleset_id);
}
}
}
@@ -335,6 +333,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)
@@ -375,7 +378,7 @@ uint64_t falco_engine::num_rules_for_ruleset(const std::string &ruleset)
return ret;
}
void falco_engine::evttypes_for_ruleset(std::string &source, std::set<uint16_t> &evttypes, const std::string &ruleset)
void falco_engine::evttypes_for_ruleset(const std::string &source, std::set<uint16_t> &evttypes, const std::string &ruleset)
{
find_source(source)->ruleset->enabled_evttypes(evttypes, find_ruleset_id(ruleset));
}
@@ -384,20 +387,20 @@ 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));
}
std::shared_ptr<gen_event_formatter> falco_engine::create_formatter(const std::string &source,
std::shared_ptr<sinsp_evt_formatter> falco_engine::create_formatter(const std::string &source,
const std::string &output) const
{
return find_source(source)->formatter_factory->create_formatter(output);
}
std::unique_ptr<std::vector<falco_engine::rule_result>> falco_engine::process_event(std::size_t source_idx,
gen_event *ev, uint16_t ruleset_id, falco_common::rule_matching strategy)
sinsp_evt *ev, uint16_t ruleset_id, falco_common::rule_matching strategy)
{
// note: there are no thread-safety guarantees on the filter_ruleset::run()
// method, but the thread-safety assumptions of falco_engine::process_event()
@@ -405,21 +408,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)
{
@@ -451,7 +440,7 @@ std::unique_ptr<std::vector<falco_engine::rule_result>> falco_engine::process_ev
}
auto res = std::make_unique<std::vector<falco_engine::rule_result>>();
for(auto rule : source->m_rules)
for(const auto& rule : source->m_rules)
{
rule_result rule_result;
rule_result.evt = ev;
@@ -469,19 +458,18 @@ std::unique_ptr<std::vector<falco_engine::rule_result>> falco_engine::process_ev
}
std::unique_ptr<std::vector<falco_engine::rule_result>> falco_engine::process_event(std::size_t source_idx,
gen_event *ev, falco_common::rule_matching strategy)
sinsp_evt *ev, falco_common::rule_matching strategy)
{
return process_event(source_idx, ev, m_default_ruleset_id, strategy);
}
std::size_t falco_engine::add_source(const std::string &source,
std::shared_ptr<gen_event_filter_factory> filter_factory,
std::shared_ptr<gen_event_formatter_factory> formatter_factory)
std::shared_ptr<sinsp_filter_factory> filter_factory,
std::shared_ptr<sinsp_evt_formatter_factory> formatter_factory)
{
// evttype_index_ruleset is the default ruleset implementation
std::shared_ptr<filter_ruleset_factory> ruleset_factory(
new evttype_index_ruleset_factory(filter_factory));
size_t idx = add_source(source, filter_factory, formatter_factory, ruleset_factory);
size_t idx = add_source(source, filter_factory, formatter_factory,
std::make_shared<evttype_index_ruleset_factory>(filter_factory));
if(source == falco_common::syscall_source)
{
@@ -492,8 +480,8 @@ std::size_t falco_engine::add_source(const std::string &source,
}
std::size_t falco_engine::add_source(const std::string &source,
std::shared_ptr<gen_event_filter_factory> filter_factory,
std::shared_ptr<gen_event_formatter_factory> formatter_factory,
std::shared_ptr<sinsp_filter_factory> filter_factory,
std::shared_ptr<sinsp_evt_formatter_factory> formatter_factory,
std::shared_ptr<filter_ruleset_factory> ruleset_factory)
{
falco_source src;
@@ -501,151 +489,120 @@ std::size_t falco_engine::add_source(const std::string &source,
src.filter_factory = filter_factory;
src.formatter_factory = formatter_factory;
src.ruleset_factory = ruleset_factory;
src.ruleset = ruleset_factory->new_ruleset();
src.ruleset = create_ruleset(src.ruleset_factory);
return m_sources.insert(src, source);
}
template <typename T> inline Json::Value sequence_to_json_array(const T& seq)
template <typename T> inline nlohmann::json sequence_to_json_array(const T& seq)
{
Json::Value ret = Json::arrayValue;
for (auto it = seq.begin(); it != seq.end(); it++)
nlohmann::json ret = nlohmann::json::array();
for (const auto& v : seq)
{
ret.append(*it);
ret.push_back(v);
}
return ret;
}
void falco_engine::describe_rule(std::string *rule, const std::vector<std::shared_ptr<sinsp_plugin>>& plugins, bool json) const
nlohmann::json falco_engine::describe_rule(std::string *rule_name, 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 most be loaded before describing them");
}
if(!json)
{
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());
}
return;
throw falco_exception("rules must be loaded before describing them");
}
// use collected and compiled info to print a json output
Json::FastWriter writer;
std::string json_str;
if(!rule)
nlohmann::json output;
if(!rule_name)
{
// 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();
auto required_engine_version = m_rule_collector->required_engine_version();
output["required_engine_version"] = required_engine_version.version.as_string();
// Store required plugin versions
Json::Value plugin_versions = Json::arrayValue;
auto required_plugin_versions = m_rule_collector.required_plugin_versions();
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_last_compile_output->rules)
nlohmann::json rules_array = nlohmann::json::array();
for(const auto& rule : m_last_compile_output->rules)
{
auto info = m_rule_collector.rules().at(r.name);
Json::Value rule;
get_json_details(rule, r, *info, plugins);
rules_array.append(rule);
auto info = m_rule_collector->rules().at(rule.name);
nlohmann::json details;
get_json_details(details, rule, *info, plugins);
rules_array.push_back(std::move(details));
}
output["rules"] = rules_array;
output["rules"] = std::move(rules_array);
// Store information about macros
Json::Value macros_array = Json::arrayValue;
for(const auto &m : m_last_compile_output->macros)
nlohmann::json macros_array = nlohmann::json::array();
for(const auto &macro : m_last_compile_output->macros)
{
auto info = m_rule_collector.macros().at(m.name);
Json::Value macro;
get_json_details(macro, m, *info, plugins);
macros_array.append(macro);
auto info = m_rule_collector->macros().at(macro.name);
nlohmann::json details;
get_json_details(details, macro, *info, plugins);
macros_array.push_back(std::move(details));
}
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_last_compile_output->lists)
// Store information about lists
nlohmann::json lists_array = nlohmann::json::array();
for(const auto &list : m_last_compile_output->lists)
{
auto info = m_rule_collector.lists().at(l.name);
Json::Value list;
get_json_details(list, l, *info, plugins);
lists_array.append(list);
auto info = m_rule_collector->lists().at(list.name);
nlohmann::json details;
get_json_details(details, list, *info, plugins);
lists_array.push_back(std::move(details));
}
output["lists"] = lists_array;
json_str = writer.write(output);
output["lists"] = std::move(lists_array);
}
else
{
// build json information for just the specified rule
auto ri = m_rule_collector.rules().at(*rule);
auto ri = m_rule_collector->rules().at(*rule_name);
if(ri == nullptr || ri->unknown_source)
{
throw falco_exception("Rule \"" + *rule + "\" is not loaded");
throw falco_exception("Rule \"" + *rule_name + "\" is not loaded");
}
auto r = m_rules.at(ri->name);
Json::Value rule;
get_json_details(rule, *r, *ri, plugins);
json_str = writer.write(rule);
auto rule = m_rules.at(ri->name);
nlohmann::json details;
get_json_details(details, *rule, *ri, plugins);
nlohmann::json rules_array = nlohmann::json::array();
rules_array.push_back(std::move(details));
output["rules"] = std::move(rules_array);
}
fprintf(stdout, "%s", json_str.c_str());
return output;
}
void falco_engine::get_json_details(
Json::Value &out,
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;
@@ -656,7 +613,7 @@ void falco_engine::get_json_details(
rule_info["enabled"] = info.enabled;
rule_info["source"] = r.source;
rule_info["tags"] = sequence_to_json_array(info.tags);
out["info"] = rule_info;
out["info"] = std::move(rule_info);
// Parse rule condition and build the non-compiled AST
// Assumption: no error because rules have already been loaded.
@@ -665,13 +622,13 @@ void falco_engine::get_json_details(
// get details related to the condition's filter
filter_details details;
filter_details compiled_details;
Json::Value json_details;
for(const auto &m : m_rule_collector.macros())
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())
for(const auto &l : m_rule_collector->lists())
{
details.known_lists.insert(l.name);
compiled_details.known_lists.insert(l.name);
@@ -720,15 +677,15 @@ void falco_engine::get_json_details(
else
{
exception_operators.insert(e.comps.item);
}
}
}
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;
nlohmann::json events;
get_json_evt_types(events, info.source, r.condition.get());
out["details"]["events"] = events;
out["details"]["events"] = std::move(events);
// Store compiled condition and output
out["details"]["condition_compiled"] = libsinsp::filter::ast::as_string(r.condition.get());
@@ -739,25 +696,25 @@ void falco_engine::get_json_details(
// - 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
Json::Value used_plugins;
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"] = used_plugins;
out["details"]["plugins"] = std::move(used_plugins);
}
void falco_engine::get_json_details(
Json::Value& out,
const falco_macro& m,
nlohmann::json& out,
const falco_macro& macro,
const rule_loader::macro_info& info,
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const
{
Json::Value macro_info;
nlohmann::json macro_info;
macro_info["name"] = m.name;
macro_info["name"] = macro.name;
macro_info["condition"] = info.cond;
out["info"] = macro_info;
out["info"] = std::move(macro_info);
// Parse the macro condition and build the non-compiled AST
// Assumption: no exception because rules have already been loaded.
@@ -766,33 +723,33 @@ void falco_engine::get_json_details(
// get details related to the condition's filter
filter_details details;
filter_details compiled_details;
Json::Value json_details;
for(const auto &m : m_rule_collector.macros())
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())
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);
filter_details_resolver().run(macro.condition.get(), compiled_details);
out["details"]["used"] = m.used;
out["details"]["used"] = macro.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);
// Store event types
Json::Value events;
get_json_evt_types(events, "", m.condition.get());
out["details"]["events"] = events;
nlohmann::json events;
get_json_evt_types(events, "", macro.condition.get());
out["details"]["events"] = std::move(events);
// Store compiled condition
out["details"]["condition_compiled"] = libsinsp::filter::ast::as_string(m.condition.get());
out["details"]["condition_compiled"] = libsinsp::filter::ast::as_string(macro.condition.get());
// 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
@@ -800,20 +757,20 @@ void falco_engine::get_json_details(
// 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"] = Json::arrayValue;
out["details"]["plugins"] = nlohmann::json::array();
}
void falco_engine::get_json_details(
Json::Value& out,
nlohmann::json& out,
const falco_list& l,
const rule_loader::list_info& info,
const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const
{
Json::Value list_info;
nlohmann::json list_info;
list_info["name"] = l.name;
// note: the syntactic definitions still has the list refs unresolved
Json::Value items = Json::arrayValue;
nlohmann::json items = nlohmann::json::array();
std::unordered_set<std::string> lists;
for(const auto &i : info.items)
{
@@ -825,19 +782,19 @@ void falco_engine::get_json_details(
lists.insert(i);
continue;
}
items.append(i);
items.push_back(std::move(i));
}
list_info["items"] = items;
out["info"] = list_info;
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"] = Json::arrayValue; // always empty
out["details"]["plugins"] = nlohmann::json::array(); // always empty
}
void falco_engine::get_json_evt_types(
Json::Value& out,
nlohmann::json& out,
const std::string& source,
libsinsp::filter::ast::expr* ast) const
{
@@ -860,7 +817,7 @@ void falco_engine::get_json_evt_types(
}
void falco_engine::get_json_used_plugins(
Json::Value& out,
nlohmann::json& out,
const std::string& source,
const std::unordered_set<std::string>& evtnames,
const std::unordered_set<std::string>& fields,
@@ -869,14 +826,17 @@ void falco_engine::get_json_used_plugins(
// note: condition and output fields may have an argument, so
// we need to isolate the field names
std::unordered_set<std::string> fieldnames;
for (auto f: fields)
for (const auto &f: fields)
{
auto argpos = f.find('[');
if (argpos != std::string::npos)
{
f = f.substr(0, argpos);
fieldnames.insert(f.substr(0, argpos));
}
else
{
fieldnames.insert(f);
}
fieldnames.insert(f);
}
std::unordered_set<std::string> used_plugins;
@@ -947,11 +907,60 @@ void falco_engine::print_stats() const
fprintf(stdout, "%s", out.c_str());
}
const stats_manager& falco_engine::get_rule_stats_manager() const
{
return m_rule_stats_manager;
}
bool falco_engine::is_source_valid(const std::string &source) const
{
return m_sources.at(source) != nullptr;
}
std::shared_ptr<sinsp_filter_factory> falco_engine::filter_factory_for_source(const std::string& source)
{
return find_source(source)->filter_factory;
}
std::shared_ptr<sinsp_filter_factory> falco_engine::filter_factory_for_source(std::size_t source_idx)
{
return find_source(source_idx)->filter_factory;
}
std::shared_ptr<sinsp_evt_formatter_factory> falco_engine::formatter_factory_for_source(const std::string& source)
{
return find_source(source)->formatter_factory;
}
std::shared_ptr<sinsp_evt_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;
@@ -966,29 +975,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,
@@ -1029,7 +1015,7 @@ bool falco_engine::check_plugin_requirements(
std::string& err) const
{
err = "";
for (const auto &alternatives : m_rule_collector.required_plugin_versions())
for(const auto &alternatives : m_rule_collector->required_plugin_versions())
{
if (!check_plugin_requirement_alternatives(plugins, alternatives, err))
{
@@ -1048,6 +1034,31 @@ bool falco_engine::check_plugin_requirements(
return true;
}
std::shared_ptr<filter_ruleset> falco_engine::create_ruleset(std::shared_ptr<filter_ruleset_factory> &ruleset_factory)
{
auto ret = ruleset_factory->new_ruleset();
ret->set_engine_state(m_engine_state);
return ret;
}
void falco_engine::fill_engine_state_funcs(filter_ruleset::engine_state_funcs &engine_state)
{
engine_state.get_ruleset = [this](const std::string &source_name, std::shared_ptr<filter_ruleset> &ruleset) -> bool
{
const falco_source *src = m_sources.at(source_name);
if(src == nullptr)
{
return false;
}
ruleset = src->ruleset;
return true;
};
};
void falco_engine::complete_rule_loading() const
{
for (const auto &src : m_sources)
@@ -1066,7 +1077,7 @@ void falco_engine::set_sampling_multiplier(double sampling_multiplier)
m_sampling_multiplier = sampling_multiplier;
}
void falco_engine::set_extra(std::string &extra, bool replace_container_info)
void falco_engine::set_extra(const std::string &extra, bool replace_container_info)
{
m_extra = extra;
m_replace_container_info = replace_container_info;

View File

@@ -15,12 +15,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// Gen filtering TODO
// - DONE Clean up use/sharing of factories amongst engine-related classes.
// - DONE Fix outputs to actually use factories
// - Review gen_filter apis to see if they have only the required interfaces
// - Fix json filterchecks to split json and evt.time filterchecks.
#pragma once
#include <atomic>
@@ -30,17 +24,16 @@ limitations under the License.
#include <nlohmann/json.hpp>
#include "gen_filter.h"
#include "filter_ruleset.h"
#include "rule_loader.h"
#include "rule_loader_reader.h"
#include "rule_loader_collector.h"
#include "rule_loader_compiler.h"
#include "stats_manager.h"
#include "falco_common.h"
#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
@@ -51,7 +44,7 @@ limitations under the License.
class falco_engine
{
public:
falco_engine(bool seed_rng=true);
explicit falco_engine(bool seed_rng=true);
virtual ~falco_engine();
// A given engine has a version which identifies the fields
@@ -71,18 +64,22 @@ public:
// 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;
void list_fields(const std::string &source, bool verbose, bool names_only, bool markdown) const;
// Provide an alternate rule reader, collector, and compiler
// to compile any rules provided via load_rules*
void set_rule_reader(std::shared_ptr<rule_loader::reader> reader);
std::shared_ptr<rule_loader::reader> get_rule_reader();
void set_rule_collector(std::shared_ptr<rule_loader::collector> collector);
std::shared_ptr<rule_loader::collector> get_rule_collector();
void set_rule_compiler(std::shared_ptr<rule_loader::compiler> compiler);
std::shared_ptr<rule_loader::compiler> get_rule_compiler();
//
// 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);
//
@@ -96,15 +93,29 @@ 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);
// Like enable_rule, but wildcards are supported and substrings are not matched
void enable_rule_wildcard(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_wildcard(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.
@@ -136,13 +147,23 @@ public:
// Print details on the given rule. If rule is NULL, print
// details on all rules.
//
void describe_rule(std::string *rule, const std::vector<std::shared_ptr<sinsp_plugin>>& plugins, bool json) const;
nlohmann::json describe_rule(std::string *rule_name, const std::vector<std::shared_ptr<sinsp_plugin>>& plugins) const;
//
// Return const /ref to rules stored in the Falco engine.
//
inline const indexed_vector<falco_rule>& get_rules() const { return m_rules; }
//
// Print statistics on how many events matched each rule.
//
void print_stats() const;
//
// Return const /ref to stats_manager to access current rules stats (how many events matched each rule so far).
//
const stats_manager& get_rule_stats_manager() const;
//
// Set the sampling ratio, which can affect which events are
// matched against the set of rules.
@@ -163,12 +184,12 @@ public:
// add k8s/container information to outputs when
// available.
//
void set_extra(std::string &extra, bool replace_container_info);
void set_extra(const std::string &extra, bool replace_container_info);
// Represents the result of matching an event against a set of
// rules.
struct rule_result {
gen_event *evt;
sinsp_evt *evt;
std::string rule;
std::string source;
falco_common::priority_type priority_num;
@@ -202,7 +223,7 @@ public:
// concurrently with the same source_idx would inherently cause data races
// and lead to undefined behavior.
std::unique_ptr<std::vector<rule_result>> process_event(std::size_t source_idx,
gen_event *ev, uint16_t ruleset_id, falco_common::rule_matching strategy);
sinsp_evt *ev, uint16_t ruleset_id, falco_common::rule_matching strategy);
//
// Wrapper assuming the default ruleset.
@@ -210,7 +231,7 @@ public:
// This inherits the same thread-safety guarantees.
//
std::unique_ptr<std::vector<rule_result>> process_event(std::size_t source_idx,
gen_event *ev, falco_common::rule_matching strategy);
sinsp_evt *ev, falco_common::rule_matching strategy);
//
// Configure the engine to support events with the provided
@@ -218,22 +239,47 @@ public:
// Return source index for fast lookup.
//
std::size_t add_source(const std::string &source,
std::shared_ptr<gen_event_filter_factory> filter_factory,
std::shared_ptr<gen_event_formatter_factory> formatter_factory);
std::shared_ptr<sinsp_filter_factory> filter_factory,
std::shared_ptr<sinsp_evt_formatter_factory> formatter_factory);
//
// Equivalent to above, but allows specifying a ruleset factory
// for the newly added source.
//
std::size_t add_source(const std::string &source,
std::shared_ptr<gen_event_filter_factory> filter_factory,
std::shared_ptr<gen_event_formatter_factory> formatter_factory,
std::shared_ptr<sinsp_filter_factory> filter_factory,
std::shared_ptr<sinsp_evt_formatter_factory> formatter_factory,
std::shared_ptr<filter_ruleset_factory> ruleset_factory);
// Return whether or not there is a valid filter/formatter
// 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<sinsp_filter_factory> filter_factory_for_source(const std::string& source);
std::shared_ptr<sinsp_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<sinsp_evt_formatter_factory> formatter_factory_for_source(const std::string& source);
std::shared_ptr<sinsp_evt_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.
@@ -241,7 +287,7 @@ public:
// typing-improved `enabled_event_codes` and `enabled_sc_codes` instead
// todo(jasondellaluce): remove this in future code refactors
//
void evttypes_for_ruleset(std::string &source,
void evttypes_for_ruleset(const std::string &source,
std::set<uint16_t> &evttypes,
const std::string &ruleset = s_default_ruleset);
@@ -263,10 +309,10 @@ public:
//
// Given a source and output string, return an
// gen_event_formatter that can format output strings for an
// sinsp_evt_formatter that can format output strings for an
// event.
//
std::shared_ptr<gen_event_formatter> create_formatter(const std::string &source,
std::shared_ptr<sinsp_evt_formatter> create_formatter(const std::string &source,
const std::string &output) const;
// The rule loader definition is aliased as it is exactly what we need
@@ -284,21 +330,58 @@ public:
std::string& err) const;
private:
// Create a ruleset using the provided factory and set the
// engine state funcs for it.
std::shared_ptr<filter_ruleset> create_ruleset(std::shared_ptr<filter_ruleset_factory>& ruleset_factory);
// Functions to retrieve state from this engine
void fill_engine_state_funcs(filter_ruleset::engine_state_funcs& engine_state);
filter_ruleset::engine_state_funcs m_engine_state;
// 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
@@ -315,40 +398,42 @@ private:
// Retrieve json details from rules, macros, lists
void get_json_details(
Json::Value& out,
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(
Json::Value& out,
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(
Json::Value& out,
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(
Json::Value& out,
nlohmann::json& out,
const std::string& source,
libsinsp::filter::ast::expr* ast) const;
void get_json_used_plugins(
Json::Value& out,
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;
std::shared_ptr<rule_loader::reader> m_rule_reader;
std::shared_ptr<rule_loader::collector> m_rule_collector;
std::shared_ptr<rule_loader::compiler> m_rule_compiler;
stats_manager m_rule_stats_manager;
uint16_t m_next_ruleset_id;
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;
std::unique_ptr<rule_loader::compile_output> m_last_compile_output;
//
// Here's how the sampling ratio and multiplier influence
@@ -379,4 +464,3 @@ private:
std::string m_extra;
bool m_replace_container_info;
};

View File

@@ -20,7 +20,7 @@ limitations under the License.
// The version of this Falco engine
#define FALCO_ENGINE_VERSION_MAJOR 0
#define FALCO_ENGINE_VERSION_MINOR 27
#define FALCO_ENGINE_VERSION_MINOR 40
#define FALCO_ENGINE_VERSION_PATCH 0
#define FALCO_ENGINE_VERSION \
@@ -34,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 "dbc34e88ab420320994d85f155dee6baff2dd018aacc00e249f897edc8b1e0f4"
#define FALCO_ENGINE_CHECKSUM "bc9d0d94ae70ef26b7cf814f62273a48b2bb4133dff0baff5f194f6f1711875a"

View File

@@ -23,7 +23,8 @@ static const std::string error_codes[] = {
"LOAD_ERR_YAML_VALIDATE",
"LOAD_ERR_COMPILE_CONDITION",
"LOAD_ERR_COMPILE_OUTPUT",
"LOAD_ERR_VALIDATE"
"LOAD_ERR_VALIDATE",
"LOAD_ERR_EXTENSION"
};
const std::string& falco::load_result::error_code_str(error_code ec)
@@ -37,7 +38,8 @@ static const std::string error_strings[] = {
"Error validating internal structure of YAML file",
"Error compiling condition",
"Error compiling output",
"Error validating rule/macro/list/exception objects"
"Error validating rule/macro/list/exception objects",
"Error in extension item"
};
const std::string& falco::load_result::error_str(error_code ec)
@@ -51,7 +53,8 @@ static const std::string error_descs[] = {
"This occurs when the internal structure of the YAML file is incorrect. Examples include not consisting of a sequence of maps, a given rule/macro/list item not having required keys, values not having the right type (e.g. the items property of a list not being a sequence), etc.",
"This occurs when a condition string can not be compiled to a filter object.",
"This occurs when an output string can not be compiled to an output object.",
"This occurs when a rule/macro/list item is incorrect. Examples include a condition field referring to an undefined macro, falco engine/plugin version mismatches, items with append without any existing item, exception fields/comps having different lengths, etc."
"This occurs when a rule/macro/list item is incorrect. Examples include a condition field referring to an undefined macro, falco engine/plugin version mismatches, items with append without any existing item, exception fields/comps having different lengths, etc.",
"This occurs when there is an error in an extension item"
};
const std::string& falco::load_result::error_desc(error_code ec)
@@ -66,7 +69,14 @@ static const std::string warning_codes[] = {
"LOAD_UNKNOWN_FILTER",
"LOAD_UNUSED_MACRO",
"LOAD_UNUSED_LIST",
"LOAD_UNKNOWN_ITEM"
"LOAD_UNKNOWN_ITEM",
"LOAD_DEPRECATED_ITEM",
"LOAD_WARNING_EXTENSION",
"LOAD_APPEND_NO_VALUES",
"LOAD_EXCEPTION_NAME_NOT_UNIQUE",
"LOAD_INVALID_MACRO_NAME",
"LOAD_INVALID_LIST_NAME",
"LOAD_COMPILE_CONDITION"
};
const std::string& falco::load_result::warning_code_str(warning_code wc)
@@ -81,7 +91,14 @@ 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",
"Warning in extension item",
"Overriding/appending with no values",
"Multiple exceptions defined with the same name",
"Invalid macro name",
"Invalid list name",
"Warning in rule condition"
};
const std::string& falco::load_result::warning_str(warning_code wc)
@@ -96,7 +113,14 @@ 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.",
"An extension item has a warning",
"A rule exception is overriding/appending with no values",
"A rule is defining multiple exceptions with the same name",
"A macro is defined with an invalid name",
"A list is defined with an invalid name",
"A rule condition or output have been parsed with a warning"
};
const std::string& falco::load_result::warning_desc(warning_code wc)

View File

@@ -34,7 +34,8 @@ public:
LOAD_ERR_YAML_VALIDATE,
LOAD_ERR_COMPILE_CONDITION,
LOAD_ERR_COMPILE_OUTPUT,
LOAD_ERR_VALIDATE
LOAD_ERR_VALIDATE,
LOAD_ERR_EXTENSION
};
// The error code as a string
@@ -54,7 +55,14 @@ public:
LOAD_UNKNOWN_FILTER,
LOAD_UNUSED_MACRO,
LOAD_UNUSED_LIST,
LOAD_UNKNOWN_ITEM
LOAD_UNKNOWN_ITEM,
LOAD_DEPRECATED_ITEM,
LOAD_WARNING_EXTENSION,
LOAD_APPEND_NO_VALUES,
LOAD_EXCEPTION_NAME_NOT_UNIQUE,
LOAD_INVALID_MACRO_NAME,
LOAD_INVALID_LIST_NAME,
LOAD_COMPILE_CONDITION
};
virtual ~load_result() = default;

View File

@@ -21,7 +21,7 @@ limitations under the License.
#include <string>
#include "falco_common.h"
#include <filter/ast.h>
#include <libsinsp/filter/ast.h>
/*!
\brief Represents a list in the Falco Engine.
@@ -83,4 +83,5 @@ struct falco_rule
std::set<std::string> exception_fields;
falco_common::priority_type priority;
std::shared_ptr<libsinsp::filter::ast::expr> condition;
std::shared_ptr<sinsp_filter> filter;
};

View File

@@ -49,21 +49,37 @@ struct falco_source
std::string name;
std::shared_ptr<filter_ruleset> ruleset;
std::shared_ptr<filter_ruleset_factory> ruleset_factory;
std::shared_ptr<gen_event_filter_factory> filter_factory;
std::shared_ptr<gen_event_formatter_factory> formatter_factory;
std::shared_ptr<sinsp_filter_factory> filter_factory;
std::shared_ptr<sinsp_evt_formatter_factory> formatter_factory;
// Used by the filter_ruleset interface. Filled in when a rule
// matches an event.
mutable std::vector<falco_rule> m_rules;
inline bool is_field_defined(const std::string& field) const
inline bool is_valid_lhs_field(const std::string& field) const
{
auto *chk = filter_factory->new_filtercheck(field.c_str());
if (chk)
// if there's at least one parenthesis we may be parsing a field
// wrapped inside one or more transformers. In those cases, the most
// rigorous analysis we can do is compiling a simple filter using
// the field as left-hand side of a comparison, and see if any error
// occurs.
if (field.find('(') != std::string::npos)
{
delete(chk);
return true;
try
{
auto filter = field;
filter.append(" exists");
sinsp_filter_compiler(filter_factory, filter).compile();
return true;
}
catch (...)
{
return false;
}
}
return false;
// otherwise, simply attempt creating a filtercheck with the given
// field name and see if we succeed
return filter_factory->new_filtercheck(field.c_str()) != nullptr;
}
};

View File

@@ -17,14 +17,18 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
#include <cstring>
#include <iomanip>
#include "falco_common.h"
#include "falco_utils.h"
#include "utils.h"
#include <libsinsp/utils.h>
#include <re2/re2.h>
#if defined(__linux__) and !defined(MINIMAL_BUILD) and !defined(__EMSCRIPTEN__)
#include <openssl/sha.h>
#endif
#include <cstring>
#include <fstream>
#include <iomanip>
#include <thread>
#define RGX_PROMETHEUS_TIME_DURATION "^((?P<y>[0-9]+)y)?((?P<w>[0-9]+)w)?((?P<d>[0-9]+)d)?((?P<h>[0-9]+)h)?((?P<m>[0-9]+)m)?((?P<s>[0-9]+)s)?((?P<ms>[0-9]+)ms)?$"
@@ -115,6 +119,50 @@ uint64_t parse_prometheus_interval(std::string interval_str)
return interval;
}
#if defined(__linux__) and !defined(MINIMAL_BUILD) and !defined(__EMSCRIPTEN__)
std::string calculate_file_sha256sum(const std::string& filename)
{
std::ifstream file(filename, std::ios::binary);
if (!file.is_open())
{
return "";
}
SHA256_CTX sha256_context;
SHA256_Init(&sha256_context);
constexpr size_t buffer_size = 4096;
char buffer[buffer_size];
while (file.read(buffer, buffer_size))
{
SHA256_Update(&sha256_context, buffer, buffer_size);
}
SHA256_Update(&sha256_context, buffer, file.gcount());
unsigned char digest[SHA256_DIGEST_LENGTH];
SHA256_Final(digest, &sha256_context);
std::stringstream ss;
for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i)
{
ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<unsigned>(digest[i]);
}
return ss.str();
}
#endif
std::string sanitize_metric_name(const std::string& name)
{
std::string sanitized_name = name;
RE2::GlobalReplace(&sanitized_name, "[^a-zA-Z0-9_:]", "_");
RE2::GlobalReplace(&sanitized_name, "_+", "_");
if (!sanitized_name.empty() && sanitized_name.back() == '_')
{
sanitized_name.pop_back();
}
return sanitized_name;
}
std::string wrap_text(const std::string& in, uint32_t indent, uint32_t line_len)
{
std::istringstream is(in);
@@ -146,7 +194,7 @@ uint32_t hardware_concurrency()
void readfile(const std::string& filename, std::string& data)
{
std::ifstream file(filename.c_str(), std::ios::in);
std::ifstream file(filename, std::ios::in);
if(file.is_open())
{
@@ -161,78 +209,46 @@ void readfile(const std::string& filename, std::string& data)
return;
}
// URI-decodes the given string by replacing percent-encoded
// characters with the actual character. Returns the decoded string.
//
// When plus_as_space is true, non-encoded plus signs in the query are decoded as spaces.
// (http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1)
std::string decode_uri(const std::string& str, bool plus_as_space)
bool matches_wildcard(const std::string &pattern, const std::string &s)
{
std::string decoded_str;
bool in_query = false;
std::string::const_iterator it = str.begin();
std::string::const_iterator end = str.end();
while(it != end)
std::string::size_type star_pos = pattern.find("*");
if(star_pos == std::string::npos)
{
char c = *it++;
if(c == '?')
{
in_query = true;
}
// spaces may be encoded as plus signs in the query
if(in_query && plus_as_space && c == '+')
{
c = ' ';
}
else if(c == '%')
{
if (it == end)
{
throw falco_exception("URI encoding: no hex digit following percent sign in " + str);
}
char hi = *it++;
if (it == end)
{
throw falco_exception("URI encoding: two hex digits must follow percent sign in " + str);
}
char lo = *it++;
if (hi >= '0' && hi <= '9')
{
c = hi - '0';
}
else if (hi >= 'A' && hi <= 'F')
{
c = hi - 'A' + 10;
}
else if (hi >= 'a' && hi <= 'f')
{
c = hi - 'a' + 10;
}
else
{
throw falco_exception("URI encoding: not a hex digit found in " + str);
}
c *= 16;
if (lo >= '0' && lo <= '9')
{
c += lo - '0';
}
else if (lo >= 'A' && lo <= 'F')
{
c += lo - 'A' + 10;
}
else if (lo >= 'a' && lo <= 'f')
{
c += lo - 'a' + 10;
}
else
{
throw falco_exception("URI encoding: not a hex digit");
}
}
decoded_str += c;
// regular match (no wildcards)
return pattern == s;
}
if(star_pos == 0)
{
// wildcard at the beginning "*something*..."
std::string::size_type next_pattern_start = pattern.find_first_not_of("*");
if(next_pattern_start == std::string::npos)
{
// pattern was just a sequence of stars *, **, ***, ... . This always matches.
return true;
}
std::string next_pattern = pattern.substr(next_pattern_start);
std::string to_find = next_pattern.substr(0, next_pattern.find("*"));
std::string::size_type lit_pos = s.find(to_find);
if(lit_pos == std::string::npos)
{
return false;
}
return matches_wildcard(next_pattern.substr(to_find.size()), s.substr(lit_pos + to_find.size()));
} else
{
// wildcard at the end or in the middle "something*else*..."
if(pattern.substr(0, star_pos) != s.substr(0, star_pos))
{
return false;
}
return matches_wildcard(pattern.substr(star_pos), s.substr(star_pos));
}
return decoded_str;
}
namespace network

View File

@@ -20,31 +20,18 @@ limitations under the License.
#pragma once
#include <sstream>
#include <fstream>
#include <iostream>
#include <string>
#include <thread>
#include <unordered_set>
#include <set>
#include <vector>
#include <cstdint>
#include <string>
#ifdef __GNUC__
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#else
#define likely(x) (x)
#define unlikely(x) (x)
namespace falco::utils
{
uint64_t parse_prometheus_interval(std::string interval_str);
#if defined(__linux__) and !defined(MINIMAL_BUILD) and !defined(__EMSCRIPTEN__)
std::string calculate_file_sha256sum(const std::string& filename);
#endif
namespace falco
{
namespace utils
{
uint64_t parse_prometheus_interval(std::string interval_str);
std::string sanitize_metric_name(const std::string& name);
std::string wrap_text(const std::string& in, uint32_t indent, uint32_t linelen);
@@ -52,12 +39,11 @@ void readfile(const std::string& filename, std::string& data);
uint32_t hardware_concurrency();
std::string decode_uri(const std::string& str, bool plus_as_space);
bool matches_wildcard(const std::string &pattern, const std::string &s);
namespace network
{
static const std::string UNIX_SCHEME("unix://");
bool is_unix_scheme(const std::string& url);
} // namespace network
} // namespace utils
} // namespace falco
} // namespace falco::utils

View File

@@ -17,9 +17,11 @@ limitations under the License.
#include "filter_details_resolver.h"
#include <stdexcept>
using namespace libsinsp::filter;
std::string get_field_name(const std::string& name, const std::string& arg)
static inline std::string get_field_name(const std::string& name, const std::string& arg)
{
std::string fld = name;
if (!arg.empty())
@@ -36,35 +38,28 @@ void filter_details::reset()
operators.clear();
lists.clear();
evtnames.clear();
transformers.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;
e->children[i]->accept(this);
m_expect_macro = false;
}
}
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;
e->children[i]->accept(this);
m_expect_macro = false;
}
}
@@ -99,36 +94,61 @@ void filter_details_resolver::visitor::visit(ast::list_expr* e)
void filter_details_resolver::visitor::visit(ast::binary_check_expr* e)
{
m_expect_macro = false;
m_details.fields.insert(get_field_name(e->field, e->arg));
m_last_node_field_name.clear();
m_expect_evtname = false;
m_expect_list = false;
e->left->accept(this);
if (m_last_node_field_name.empty())
{
throw std::runtime_error("can't find field info in binary check expression");
}
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 = m_last_node_field_name == "evt.type" || m_last_node_field_name == "evt.asynctype";
e->right->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(get_field_name(e->field, e->arg));
m_last_node_field_name.clear();
e->left->accept(this);
if (m_last_node_field_name.empty())
{
throw std::runtime_error("can't find field info in unary check expression");
}
m_details.fields.insert(m_last_node_field_name);
m_details.operators.insert(e->op);
}
void filter_details_resolver::visitor::visit(ast::identifier_expr* e)
{
// todo(jasondellaluce): maybe throw an error if we encounter an unknown macro?
if(m_details.known_macros.find(e->identifier) != m_details.known_macros.end())
{
m_details.macros.insert(e->identifier);
}
}
void filter_details_resolver::visitor::visit(ast::value_expr* e)
{
if (m_expect_macro)
{
if(m_details.known_macros.find(e->value) != m_details.known_macros.end())
{
m_details.macros.insert(e->value);
}
// todo(jasondellaluce): should we throw an error if we
// encounter an unknown macro?
}
else if (m_expect_evtname)
if (m_expect_evtname)
{
m_details.evtnames.insert(e->value);
}
}
void filter_details_resolver::visitor::visit(ast::field_expr* e)
{
m_last_node_field_name = get_field_name(e->field, e->arg);
m_details.fields.insert(m_last_node_field_name);
}
void filter_details_resolver::visitor::visit(ast::field_transformer_expr* e)
{
m_details.transformers.insert(e->transformer);
e->value->accept(this);
}

View File

@@ -17,23 +17,24 @@ limitations under the License.
#pragma once
#include <filter/parser.h>
#include <libsinsp/filter/parser.h>
#include <string>
#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;
std::unordered_set<std::string> transformers;
void reset();
};
@@ -47,37 +48,38 @@ 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) :
explicit visitor(filter_details& details) :
m_details(details),
m_expect_list(false),
m_expect_macro(false),
m_expect_evtname(false) {}
m_expect_evtname(false),
m_last_node_field_name() {}
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;
void visit(libsinsp::filter::ast::not_expr* e) override;
void visit(libsinsp::filter::ast::identifier_expr* e) override;
void visit(libsinsp::filter::ast::value_expr* e) override;
void visit(libsinsp::filter::ast::list_expr* e) override;
void visit(libsinsp::filter::ast::unary_check_expr* e) override;
void visit(libsinsp::filter::ast::binary_check_expr* e) override;
void visit(libsinsp::filter::ast::field_expr* e) override;
void visit(libsinsp::filter::ast::field_transformer_expr* e) override;
filter_details& m_details;
bool m_expect_list;
bool m_expect_macro;
bool m_expect_evtname;
std::string m_last_node_field_name;
};
};

View File

@@ -20,23 +20,6 @@ limitations under the License.
using namespace libsinsp::filter;
bool filter_macro_resolver::run(libsinsp::filter::ast::expr*& filter)
{
m_unknown_macros.clear();
m_resolved_macros.clear();
m_errors.clear();
visitor v(m_errors, m_unknown_macros, m_resolved_macros, m_macros);
v.m_node_substitute = nullptr;
filter->accept(&v);
if (v.m_node_substitute)
{
delete filter;
filter = v.m_node_substitute.release();
}
return !m_resolved_macros.empty();
}
bool filter_macro_resolver::run(std::shared_ptr<libsinsp::filter::ast::expr>& filter)
{
m_unknown_macros.clear();
@@ -54,8 +37,8 @@ bool filter_macro_resolver::run(std::shared_ptr<libsinsp::filter::ast::expr>& fi
}
void filter_macro_resolver::set_macro(
std::string name,
std::shared_ptr<libsinsp::filter::ast::expr> macro)
const std::string& name,
const std::shared_ptr<libsinsp::filter::ast::expr>& macro)
{
m_macros[name] = macro;
}
@@ -118,8 +101,6 @@ void filter_macro_resolver::visitor::visit(ast::list_expr* e)
void filter_macro_resolver::visitor::visit(ast::binary_check_expr* e)
{
// avoid exploring checks, so that we can be sure that each
// value_expr* node visited is a macro identifier
m_node_substitute = nullptr;
}
@@ -130,10 +111,22 @@ void filter_macro_resolver::visitor::visit(ast::unary_check_expr* e)
void filter_macro_resolver::visitor::visit(ast::value_expr* e)
{
// we are supposed to get here only in case
// of identier-only children from either a 'not',
// an 'and' or an 'or'.
const auto& macro = m_macros.find(e->value);
m_node_substitute = nullptr;
}
void filter_macro_resolver::visitor::visit(ast::field_expr* e)
{
m_node_substitute = nullptr;
}
void filter_macro_resolver::visitor::visit(ast::field_transformer_expr* e)
{
m_node_substitute = nullptr;
}
void filter_macro_resolver::visitor::visit(ast::identifier_expr* e)
{
const auto& macro = m_macros.find(e->identifier);
if (macro != m_macros.end() && macro->second) // skip null-ptr macros
{
// note: checks for loop detection
@@ -143,7 +136,7 @@ void filter_macro_resolver::visitor::visit(ast::value_expr* e)
auto msg = "reference loop in macro '" + macro->first + "'";
m_errors.push_back({msg, e->get_pos()});
m_node_substitute = nullptr;
m_unknown_macros.push_back({e->value, e->get_pos()});
m_unknown_macros.push_back({e->identifier, e->get_pos()});
return;
}
@@ -157,12 +150,12 @@ void filter_macro_resolver::visitor::visit(ast::value_expr* e)
{
m_node_substitute = std::move(new_node);
}
m_resolved_macros.push_back({e->value, e->get_pos()});
m_resolved_macros.push_back({e->identifier, e->get_pos()});
m_macros_path.pop_back();
}
else
{
m_node_substitute = nullptr;
m_unknown_macros.push_back({e->value, e->get_pos()});
m_unknown_macros.push_back({e->identifier, e->get_pos()});
}
}

View File

@@ -17,7 +17,7 @@ limitations under the License.
#pragma once
#include <filter/parser.h>
#include <libsinsp/filter/parser.h>
#include <string>
#include <unordered_set>
#include <unordered_map>
@@ -35,16 +35,11 @@ class filter_macro_resolver
according with all the definitions added through set_macro(),
by replacing the reference with a clone of the macro AST.
\param filter The filter AST to be processed. Note that the pointer
is passed by reference and be modified in order to apply
is passed by reference and be transformed in order to apply
the substutions. In that case, the old pointer is owned by this
class and is deleted automatically.
\return true if at least one of the defined macros is resolved
*/
bool run(libsinsp::filter::ast::expr*& filter);
/*!
\brief Version of run() that works with shared pointers
*/
bool run(std::shared_ptr<libsinsp::filter::ast::expr>& filter);
/*!
@@ -56,12 +51,12 @@ class filter_macro_resolver
\param macro The AST of the macro.
*/
void set_macro(
std::string name,
std::shared_ptr<libsinsp::filter::ast::expr> macro);
const std::string& name,
const std::shared_ptr<libsinsp::filter::ast::expr>& macro);
/*!
\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;
@@ -86,6 +81,18 @@ class filter_macro_resolver
*/
const std::vector<value_info>& get_errors() const;
/*!
\brief Clears the resolver by resetting all state related to
known macros and everything related to the previous resolution run.
*/
inline void clear()
{
m_errors.clear();
m_unknown_macros.clear();
m_resolved_macros.clear();
m_macros.clear();
}
private:
typedef std::unordered_map<
std::string,
@@ -103,10 +110,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;
@@ -118,10 +121,13 @@ class filter_macro_resolver
void visit(libsinsp::filter::ast::and_expr* e) override;
void visit(libsinsp::filter::ast::or_expr* e) override;
void visit(libsinsp::filter::ast::not_expr* e) override;
void visit(libsinsp::filter::ast::identifier_expr* e) override;
void visit(libsinsp::filter::ast::value_expr* e) override;
void visit(libsinsp::filter::ast::list_expr* e) override;
void visit(libsinsp::filter::ast::unary_check_expr* e) override;
void visit(libsinsp::filter::ast::binary_check_expr* e) override;
void visit(libsinsp::filter::ast::field_expr* e) override;
void visit(libsinsp::filter::ast::field_transformer_expr* e) override;
};
std::vector<value_info> m_errors;

View File

@@ -0,0 +1,28 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright (C) 2024 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 "filter_ruleset.h"
void filter_ruleset::set_engine_state(const filter_ruleset::engine_state_funcs& engine_state)
{
m_engine_state = engine_state;
}
filter_ruleset::engine_state_funcs& filter_ruleset::get_engine_state()
{
return m_engine_state;
}

View File

@@ -18,21 +18,38 @@ limitations under the License.
#pragma once
#include "falco_rule.h"
#include <filter/ast.h>
#include <filter.h>
#include <event.h>
#include <gen_filter.h>
#include <events/sinsp_events.h>
#include "rule_loader_compile_output.h"
#include <libsinsp/filter/ast.h>
#include <libsinsp/filter.h>
#include <libsinsp/event.h>
#include <libsinsp/events/sinsp_events.h>
/*!
\brief Manages a set of rulesets. A ruleset is a set of
enabled rules that is able to process events and find matches for those rules.
*/
class filter_ruleset
{
public:
// A set of functions that can be used to retrieve state from
// the falco engine that created this ruleset.
struct engine_state_funcs
{
using ruleset_retriever_func_t = std::function<bool(const std::string &, std::shared_ptr<filter_ruleset> &ruleset)>;
ruleset_retriever_func_t get_ruleset;
};
enum class match_type {
exact, substring, wildcard
};
virtual ~filter_ruleset() = default;
void set_engine_state(const engine_state_funcs &engine_state);
engine_state_funcs &get_engine_state();
/*!
\brief Adds a rule and its filtering filter + condition inside the manager.
This method only adds the rule inside the internal collection,
@@ -47,9 +64,38 @@ public:
*/
virtual void add(
const falco_rule& rule,
std::shared_ptr<gen_event_filter> filter,
std::shared_ptr<sinsp_filter> filter,
std::shared_ptr<libsinsp::filter::ast::expr> condition) = 0;
/*!
\brief Adds all rules contained in the provided
rule_loader::compile_output struct. Only
those rules with the provided source and those rules
with priority >= min_priority should be added. The
intent is that this replaces add(). However, we retain
add() for backwards compatibility. Any rules added via
add() are also added to this ruleset. The default
implementation iterates over rules and calls add(),
but can be overridden.
\param rule The compile output.
\param min_priority Only add rules with priority above this priority.
\param source Only add rules with source equal to this source.
*/
virtual void add_compile_output(
const rule_loader::compile_output& compile_output,
falco_common::priority_type min_priority,
const std::string& source)
{
for (const auto& rule : compile_output.rules)
{
if(rule.priority <= min_priority &&
rule.source == source)
{
add(rule, rule.filter, rule.condition);
}
}
};
/*!
\brief Erases the internal state. All rules are disabled in each
ruleset, and all the rules defined with add() are removed.
@@ -71,7 +117,7 @@ public:
\param ruleset_id The id of the ruleset to be used
*/
virtual bool run(
gen_event *evt,
sinsp_evt *evt,
falco_rule& match,
uint16_t ruleset_id) = 0;
@@ -84,7 +130,7 @@ public:
\param ruleset_id The id of the ruleset to be used
*/
virtual bool run(
gen_event *evt,
sinsp_evt *evt,
std::vector<falco_rule>& matches,
uint16_t ruleset_id) = 0;
@@ -125,31 +171,37 @@ public:
/*!
\brief Find those rules matching the provided substring and enable
them in the provided ruleset.
\param substring Substring used to match rule names.
If empty, all rules are matched.
\param match_exact If true, substring must be an exact match for a
given rule name. Otherwise, any rules having substring as a substring
in the rule name are enabled/disabled.
\param pattern Pattern used to match rule names.
\param match How to match the pattern against rules:
- exact: rules that has the same exact name as the pattern are matched
- substring: rules having the pattern as a substring in the rule are matched.
An empty pattern matches all rules.
- wildcard: rules with names that satisfies a wildcard (*) pattern are matched.
A "*" pattern matches all rules.
Wildcards can appear anywhere in the pattern (e.g. "*hello*world*")
\param ruleset_id The id of the ruleset to be used
*/
virtual void enable(
const std::string &substring,
bool match_exact,
const std::string &pattern,
match_type match,
uint16_t ruleset_id) = 0;
/*!
\brief Find those rules matching the provided substring and disable
them in the provided ruleset.
\param substring Substring used to match rule names.
If empty, all rules are matched.
\param match_exact If true, substring must be an exact match for a
given rule name. Otherwise, any rules having substring as a substring
in the rule name are enabled/disabled.
\param pattern Pattern used to match rule names.
\param match How to match the pattern against rules:
- exact: rules that has the same exact name as the pattern are matched
- substring: rules having the pattern as a substring in the rule are matched.
An empty pattern matches all rules.
- wildcard: rules with names that satisfies a wildcard (*) pattern are matched.
A "*" pattern matches all rules.
Wildcards can appear anywhere in the pattern (e.g. "*hello*world*")
\param ruleset_id The id of the ruleset to be used
*/
virtual void disable(
const std::string &substring,
bool match_exact,
const std::string &pattern,
match_type match,
uint16_t ruleset_id) = 0;
/*!
@@ -181,6 +233,9 @@ public:
virtual void disable_tags(
const std::set<std::string> &tags,
uint16_t ruleset_id) = 0;
private:
engine_state_funcs m_engine_state;
};
/*!

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