Compare commits

..

37 Commits

Author SHA1 Message Date
Federico Di Pierro
ab403687e5 wip
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-04-04 09:43:23 +02:00
Federico Di Pierro
e49e6066c7 wip
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-04-04 09:43:22 +02:00
dependabot[bot]
2b29ff7ee6 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `e0646a0` to `694adf5`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](e0646a024f...694adf59e0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-03 20:05:46 +02:00
Melissa Kilby
0b6e243582 cleanup(app_acions): fine-tune base_syscalls.repair behavior
Co-authored-by: Jason Dellaluce <jasondellaluce@gmail.com>
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-03-30 19:08:33 +02:00
Melissa Kilby
e178174a93 update(cmake,userspace): bumped to libs master
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-03-30 19:08:33 +02:00
Melissa Kilby
dad382edd6 cleanup(config): adjust description for base_syscalls option
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-03-30 19:08:33 +02:00
Melissa Kilby
78daafb56c cleanup(app_actions): finalize base_syscalls.repair option
Co-authored-by: Jason Dellaluce <jasondellaluce@gmail.com>
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-03-30 19:08:33 +02:00
Jason Dellaluce
2b93a79521 refactor: apply review suggestions
Co-authored-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-03-30 19:08:33 +02:00
Melissa Kilby
3e0f0d3692 cleanup(unit_tests): revert some test extensions in interim
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-03-30 19:08:33 +02:00
Melissa Kilby
ea3571564b cleanup(unit_tests): add selection_custom_base_set_repair tests
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-03-30 19:08:33 +02:00
Melissa Kilby
e360175c15 fix(app_actions): enforce PPM_SC_SCHED_PROCESS_EXIT for base_syscalls.custom_set
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-03-30 19:08:33 +02:00
Melissa Kilby
692abf71eb new(app_actions): add base_syscalls.repair option
See https://github.com/falcosecurity/falco/issues/2433

Co-authored-by: Jason Dellaluce <jasondellaluce@gmail.com>
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-03-30 19:08:33 +02:00
Melissa Kilby
1d66eb4d6d cleanup(app_actions): add warnings for invalid syscalls in user base_syscalls set
Signed-off-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-03-30 19:08:33 +02:00
Aldo Lacuku
31335d3c3b new(falco/config): add new configuration for http_output
Support for user provided CA certificate that can verify the remote server. Users
can provide path to the CA certiface store by providing a path to the dir or to the
CA store file. If needed users can decide to tell Falco to not verify the server.

Signed-off-by: Aldo Lacuku <aldo@lacuku.eu>
2023-03-30 17:11:33 +02:00
dependabot[bot]
7f4fb624dd build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `0b0f50f` to `e0646a0`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](0b0f50fdf6...e0646a024f)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-29 21:31:31 +02:00
Federico Di Pierro
0b7ca2823e chore(userspace): apply review suggestions.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>

Co-authored-by: Jason Dellaluca <jasondellaluce@gmail.com>
2023-03-28 19:01:30 +02:00
Federico Di Pierro
b2e03b1938 chore(userspace): syscall_drop_failed -> syscall_drop_failed_exit.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>

Co-authored-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-03-28 19:01:30 +02:00
Federico Di Pierro
70c6c93389 chore(userspace): improved wording.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>

Co-authored-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2023-03-28 19:01:30 +02:00
Federico Di Pierro
bd13ba70e3 update(cmake): bumped to latest libs/driver.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-03-28 19:01:30 +02:00
Federico Di Pierro
f8f7e73a7f update(docs): properly document new option in config file.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-03-28 19:01:30 +02:00
Federico Di Pierro
bf5e340833 new(userspace/falco): added syscall_drop_failed option to drop failed syscalls exit events.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-03-28 19:01:30 +02:00
Federico Di Pierro
804e6fc122 update(cmake): bumped libs to latest master.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-03-28 19:01:30 +02:00
dependabot[bot]
4836978ba9 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `3f52480` to `0b0f50f`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](3f52480618...0b0f50fdf6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-23 10:50:12 +01:00
Federico Di Pierro
e6078c8d16 chore(userspace): updated fields checksum.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-03-22 11:17:07 +01:00
Federico Di Pierro
17b170b4f9 update(cmake,userspace): bumped to libs master.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
2023-03-22 11:17:07 +01:00
dependabot[bot]
e4d575b10d build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `dab4474` to `3f52480`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](dab44746af...3f52480618)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-21 12:24:44 +01:00
rabbitstack
03285f4140 define Windows equivalent for srandom and random functions
Signed-off-by: rabbitstack <nedim.sabic@sysdig.com>
2023-03-17 10:23:26 +01:00
dependabot[bot]
9c5d643a90 build(deps): Bump submodules/falcosecurity-rules
Bumps [submodules/falcosecurity-rules](https://github.com/falcosecurity/rules) from `5b6e2c0` to `dab4474`.
- [Release notes](https://github.com/falcosecurity/rules/releases)
- [Commits](5b6e2c0241...dab44746af)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-17 10:20:26 +01:00
Jason Dellaluce
93ae6bb609 chore(userspace/falco): fix codespell typos
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-03-15 17:54:49 +01:00
Jason Dellaluce
e07e3abfb5 update(userspace/falco): implement debouncing logic in restart handler
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-03-15 17:54:49 +01:00
Jason Dellaluce
3f69d46f9a update(userspace/falco): minor compilation improvements
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-03-15 17:54:49 +01:00
Jason Dellaluce
647441c06c fix(userspace/falco): solve gettid compilation issues
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-03-15 17:54:49 +01:00
Jason Dellaluce
cd155ed6f5 refactor(userspace/falco): update actions to use new hot restarter utility with dry-run safetyc checks
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-03-15 17:54:49 +01:00
Jason Dellaluce
561022ebb6 new(userspace/falco): add utility for handling hot app restarts
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-03-15 17:54:49 +01:00
Jason Dellaluce
af46833ad3 update(userspace/falco): make cmdline options simpler and copyable
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-03-15 17:54:49 +01:00
Jason Dellaluce
e40369648c fix(userspace/falco): solve minor compilation flaws
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-03-15 17:54:49 +01:00
Jason Dellaluce
ee7fa1cb06 new(usersapce/falco): add an app option for dry-run
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
2023-03-15 17:54:49 +01:00
33 changed files with 766 additions and 212 deletions

View File

@@ -107,10 +107,8 @@ if(BUILD_WARNINGS_AS_ERRORS)
set(CMAKE_COMMON_FLAGS "${CMAKE_COMMON_FLAGS} -Wextra -Werror ${CMAKE_SUPPRESSED_WARNINGS}")
endif()
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_EXTENSIONS OFF)
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++0x ${CMAKE_COMMON_FLAGS} -Wno-class-memaccess")
set(CMAKE_C_FLAGS_DEBUG "${FALCO_EXTRA_DEBUG_FLAGS}")
set(CMAKE_CXX_FLAGS_DEBUG "${FALCO_EXTRA_DEBUG_FLAGS}")

View File

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

View File

@@ -19,7 +19,7 @@ message(STATUS "Libs version: ${FALCOSECURITY_LIBS_VERSION}")
ExternalProject_Add(
falcosecurity-libs
URL "https://github.com/Andreagit97/libs/archive/${FALCOSECURITY_LIBS_VERSION}.tar.gz"
URL "https://github.com/falcosecurity/libs/archive/${FALCOSECURITY_LIBS_VERSION}.tar.gz"
URL_HASH "${FALCOSECURITY_LIBS_CHECKSUM}"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""

View File

@@ -27,8 +27,8 @@ else()
# In case you want to test against another falcosecurity/libs version (or branch, or commit) just pass the variable -
# ie., `cmake -DFALCOSECURITY_LIBS_VERSION=dev ..`
if(NOT FALCOSECURITY_LIBS_VERSION)
set(FALCOSECURITY_LIBS_VERSION "ea32dfb4510ad6d9dcdfa6c40c0ba062dcc2bfb5")
set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=31cc9ed4479daf210ccefcf419bd64f8e7c475d441453db368bde72e653774b6")
set(FALCOSECURITY_LIBS_VERSION "79f9664cde383950bc084ca1d4230afe79509242")
# set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=4d390bdde2c061491cb73d5703a2e0db7bd681a4738b4a9e50252fff3628dd29")
endif()
# cd /path/to/build && cmake /path/to/source

View File

@@ -170,6 +170,13 @@ syscall_event_drops:
syscall_event_timeouts:
max_consecutives: 1000
# Enabling this option allows Falco to drop failed syscalls exit events
# in the kernel driver before the event is pushed onto the ring buffer.
# This can enable some small optimization both in CPU usage and ring buffer usage,
# possibly leading to lower number of event losses.
# Be careful: enabling it also means losing a bit of visibility on the system.
syscall_drop_failed_exit: false
# --- [Description]
#
# This is an index that controls the dimension of the syscall buffers.
@@ -401,6 +408,15 @@ http_output:
enabled: false
url: http://some.url
user_agent: "falcosecurity/falco"
# Tell Falco to not verify the remote server.
insecure: false
# Path to the CA certificate that can verify the remote server.
ca_cert: ""
# Path to a specific file that will be used as the CA certificate store.
ca_bundle: ""
# Path to a folder that will be used as the CA certificate store. CA certificate need to be
# stored as indivitual PEM files in this directory.
ca_path: "/etc/ssl/certs"
# Falco supports running a gRPC server with two main binding types
# 1. Over the network with mandatory mutual TLS authentication (mTLS)
@@ -444,66 +460,87 @@ metadata_download:
watch_freq_sec: 1
# base_syscalls ! Use with caution !
# base_syscalls ! Use with caution, read carefully !
#
# --- [Description]
#
# With this option you are in full control of the total set of syscalls that
# With this option you are in full control of the set of syscalls that
# Falco will enable in the kernel for active tracing.
# All syscalls and events from each enabled Falco rule will automatically be activated
# even when choosing this option. This option provides full end user control to specifically
# define a static set of base syscalls that will be activated in addition to the
# All syscalls and events from each enabled Falco rule are activated
# even when choosing this option. This option allows you to define a
# set of base syscalls that will be activated in addition to the
# syscalls defined in the rules.
#
# When using this option, Falco does not add any other syscalls that may be needed for
# Falco's state engine. The union of all syscalls from the rules (including resolved macros)
# and the ones specified here compose the final set of syscalls that are traced in the kernel.
# This puts the end user in the driver seat, but if not used correctly Falco logs may be
# incomplete or wrong. This option however can be very useful to lower CPU utilization and
# allowing you to tailor Falco to specific environments according to your
# organization's threat model and security posture as well as cost budget.
# !!! When NOT using this option, Falco defaults to adding a static set of syscalls in addition
# to the rules system calls you need for Falco's state engine build-up and life-cycle management.
# You may ask yourself why do we need to activate syscalls in addition to the rules?
#
# Falco requires a set of syscalls to build up state in userspace. This is because for
# example when spawning a new process or creating a network connection more than one syscall
# is involved. Furthermore, properties of a process during its life time can be modified
# by syscalls. Falco takes care of this by activating more syscalls than the ones defined
# in the rules and by managing a smart process cache table in userspace.
# Processes are purged when a process exits.
#
# Looking back to what this option does, it activates all syscalls from the rules
# (including resolved macros) and the ones specified here.
#
# This puts the end user in the driver seat to tell Falco what it needs, but if not used correctly
# Falco logs may be incomplete or wrong or Falco won't work at all. This option however can be
# very useful to lower CPU utilization and allowing you to tailor Falco to specific environments
# according to your organization's threat model and cost budget.
#
# !!! When NOT using this option, Falco defaults to adding a static (more verbose) set of syscalls
# in addition to the rules system calls Falco needs for its state engine build-up and life-cycle management.
#
# `base_syscalls.repair` is an experimental alternative to Falco's default state engine enforcement.
# `base_syscalls.repair` is designed to be the most resourceful option to ensure Falco runs correctly
# while activating a most minimal set of additional syscalls. The recommendations listed in the suggestions
# section is effectively what `base_syscalls.repair` is doing in an automated manner. `base_syscalls.repair`
# can be used with an empty custom set.
#
# --- [Usage]
#
# List of system calls names (<syscall-name>) plus negative ("!<syscall-name>") notation supported.
#
# base_syscalls: [<syscall-name>, <syscall-name>, "!<syscall-name>"]
# base_syscalls.repair: <bool>
# base_syscalls.custom_set: [<syscall-name>, <syscall-name>, "!<syscall-name>"]
#
#
# --- [Suggestions]
#
# Here are a few recommendations that may help you to use the full power of this option:
# Here are a few recommendations that may help you.
# Setting `base_syscalls.repair: true` automates these recommendations for you.
#
# Consider to at minimum add the following syscalls regardless of the syscalls used in the rules.
#
# [clone, clone3, fork, vfork, execve, execveat, close]
#
# This is because some Falco fields you may output for an execve* system call are retrieved
# from the associated "clone", "clone3", "fork", "vfork" syscall when spawning a new process.
# The "close" system call is used to purge file descriptors from Falco's internal
# thread / process cache table and therefore should always be added when you have rules around fds
# This is because some Falco fields for an execve* system call are retrieved
# from the associated `clone`, `clone3`, `fork`, `vfork` syscall when spawning a
# new process. The `close` system call is used to purge file descriptors from Falco's
# internal thread / process cache table and should always be added when you have
# rules around file descriptors.
# (e.g. open, openat, openat2, socket, connect, accept, accept4 ... and many more)
#
# When network syscalls are used in rules we recommend to at minimum set
#
# [clone, clone3, fork, vfork, execve, execveat, close, socket, bind, getsockopt]
#
# It turns out that while you absolutely can log connect or accept* syscalls without the socket
# system call, the log however would not contain the ip tuples.
# For listen and accept* system calls you also need the bind system call.
# It turns out that while you can log `connect` or `accept*` syscalls without the
# socket system call, the log however would not contain the ip tuples.
# For `listen` and `accept*` system calls you also need the `bind` system call.
#
# Lastly, if you care about the correct uid, gid or sid, pgid of a process when that process then
# opens a file or makes a network connection or any other action, consider also
# adding the following syscalls:
# Lastly, if you care about the correct `uid`, `gid` or `sid`, `pgid` of a process when the
# running process opens a file or makes a network connection, consider adding the following syscalls:
#
# setresuid, setsid, setuid, setgid, setpgid, setresgid, setsid, capset, chdir, chroot, fchdir
#
# Only exclude syscalls, e.g. "!mprotect" if you need a fast deployment update (overriding rules),
# else rather remove unwanted or not needed syscalls from the Falco rules.
# We recommend to only exclude syscalls, e.g. "!mprotect" if you need a fast deployment update
# (overriding rules), else remove unwanted syscalls from the Falco rules.
#
# Passing `-o "log_level=debug"` to Falco's cmd args during a dry-run will print the
# final set of syscalls to STDOUT.
base_syscalls: []
base_syscalls:
repair: false
custom_set: []

View File

@@ -23,7 +23,7 @@ limitations under the License.
#include <gtest/gtest.h>
#define ASSERT_NAMES_EQ(a, b) { \
ASSERT_EQ(_order(a).size(), _order(b).size()); \
EXPECT_EQ(_order(a).size(), _order(b).size()); \
ASSERT_EQ(_order(a), _order(b)); \
}
@@ -47,7 +47,7 @@ static std::string s_sample_ruleset = "sample-ruleset";
static std::string s_sample_source = falco_common::syscall_source;
static strset_t s_sample_filters = {
"evt.type=connect or evt.type=accept",
"evt.type=connect or evt.type=accept or evt.type=accept4 or evt.type=umount2",
"evt.type in (open, ptrace, mmap, execve, read, container)",
"evt.type in (open, execve, mprotect) and not evt.type=mprotect"};
@@ -99,7 +99,7 @@ TEST(ConfigureInterestingSets, engine_codes_syscalls_set)
auto rules_event_set = 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", "open", "ptrace", "mmap", "execve", "read", "container"}));
"connect", "accept", "accept4", "umount2", "open", "ptrace", "mmap", "execve", "read", "container"}));
// 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
@@ -107,7 +107,7 @@ TEST(ConfigureInterestingSets, engine_codes_syscalls_set)
auto rules_sc_set = engine->sc_codes_for_ruleset(s_sample_source);
auto rules_sc_names = libsinsp::events::sc_set_to_names(rules_sc_set);
ASSERT_NAMES_EQ(rules_sc_names, strset_t({
"connect", "accept", "accept4", "open", "ptrace", "mmap", "execve", "read"}));
"connect", "accept", "accept4", "umount2", "open", "ptrace", "mmap", "execve", "read"}));
}
TEST(ConfigureInterestingSets, preconditions_postconditions)
@@ -158,7 +158,7 @@ TEST(ConfigureInterestingSets, engine_codes_nonsyscalls_set)
// This is a good example of information loss from ppm_event_code <-> ppm_sc_code.
auto generic_names = libsinsp::events::event_set_to_names({ppm_event_code::PPME_GENERIC_E});
auto expected_names = strset_t({
"connect", "accept", "open", "ptrace", "mmap", "execve", "read", "container", // ruleset
"connect", "accept", "accept4", "umount2", "open", "ptrace", "mmap", "execve", "read", "container", // ruleset
"procexit", "switch", "pluginevent"}); // from non-syscall event filters
expected_names.insert(generic_names.begin(), generic_names.end());
ASSERT_NAMES_EQ(rules_event_names, expected_names);
@@ -166,7 +166,7 @@ TEST(ConfigureInterestingSets, engine_codes_nonsyscalls_set)
auto rules_sc_set = engine->sc_codes_for_ruleset(s_sample_source);
auto rules_sc_names = libsinsp::events::sc_set_to_names(rules_sc_set);
ASSERT_NAMES_EQ(rules_sc_names, strset_t({
"connect", "accept", "accept4", "open", "ptrace", "mmap", "execve", "read",
"connect", "accept", "accept4", "umount2", "open", "ptrace", "mmap", "execve", "read",
"syncfs", "fanotify_init", // from generic event filters
}));
}
@@ -185,11 +185,11 @@ TEST(ConfigureInterestingSets, selection_not_allevents)
// also check if a warning has been printed in stderr
// check that the final selected set is the one expected
ASSERT_NE(s.selected_sc_set.size(), 0);
ASSERT_GT(s.selected_sc_set.size(), 1);
auto selected_sc_names = libsinsp::events::sc_set_to_names(s.selected_sc_set);
auto expected_sc_names = strset_t({
// note: we expect the "read" syscall to have been erased
"connect", "accept", "open", "ptrace", "mmap", "execve", // from ruleset
"connect", "accept", "accept4", "umount2", "open", "ptrace", "mmap", "execve", // from ruleset
"clone", "clone3", "fork", "vfork", // from sinsp state set (spawned_process)
"socket", "bind", "close" // from sinsp state set (network, files)
});
@@ -228,11 +228,11 @@ TEST(ConfigureInterestingSets, selection_allevents)
// also check if a warning has not been printed in stderr
// check that the final selected set is the one expected
ASSERT_NE(s.selected_sc_set.size(), 0);
ASSERT_GT(s.selected_sc_set.size(), 1);
auto selected_sc_names = libsinsp::events::sc_set_to_names(s.selected_sc_set);
auto expected_sc_names = strset_t({
// note: we expect the "read" syscall to not be erased
"connect", "accept", "open", "ptrace", "mmap", "execve", "read", // from ruleset
"connect", "accept", "accept4", "umount2", "open", "ptrace", "mmap", "execve", "read", // from ruleset
"clone", "clone3", "fork", "vfork", // from sinsp state set (spawned_process)
"socket", "bind", "close" // from sinsp state set (network, files)
});
@@ -251,6 +251,7 @@ TEST(ConfigureInterestingSets, selection_generic_evts)
{
// run app action with fake engine and without the `-A` option
falco::app::state s;
s.options.all_events = false;
auto filters = s_sample_filters;
filters.insert(s_sample_generic_filters.begin(), s_sample_generic_filters.end());
s.engine = mock_engine_from_filters(filters);
@@ -259,16 +260,18 @@ TEST(ConfigureInterestingSets, selection_generic_evts)
ASSERT_EQ(result.errstr, "");
// check that the final selected set is the one expected
ASSERT_NE(s.selected_sc_set.size(), 0);
ASSERT_GT(s.selected_sc_set.size(), 1);
auto selected_sc_names = libsinsp::events::sc_set_to_names(s.selected_sc_set);
auto expected_sc_names = strset_t({
// note: we expect the "read" syscall to not be erased
"connect", "accept", "open", "ptrace", "mmap", "execve", // from ruleset
"connect", "accept", "accept4", "umount2", "open", "ptrace", "mmap", "execve", // from ruleset
"syncfs", "fanotify_init", // from ruleset (generic events)
"clone", "clone3", "fork", "vfork", // from sinsp state set (spawned_process)
"socket", "bind", "close" // from sinsp state set (network, files)
});
ASSERT_NAMES_CONTAIN(selected_sc_names, expected_sc_names);
auto unexpected_sc_names = libsinsp::events::sc_set_to_names(libsinsp::events::io_sc_set());
ASSERT_NAMES_NOCONTAIN(selected_sc_names, unexpected_sc_names);
}
// expected combinations precedence:
@@ -285,7 +288,8 @@ TEST(ConfigureInterestingSets, selection_custom_base_set)
auto default_base_set = libsinsp::events::sinsp_state_sc_set();
// non-empty custom base set (both positive and negative)
s.config->m_base_syscalls = {"syncfs", "!accept"};
s.config->m_base_syscalls_repair = false;
s.config->m_base_syscalls_custom_set = {"syncfs", "!accept"};
auto result = falco::app::actions::configure_interesting_sets(s);
ASSERT_TRUE(result.success);
ASSERT_EQ(result.errstr, "");
@@ -297,48 +301,51 @@ TEST(ConfigureInterestingSets, selection_custom_base_set)
// note: `accept` is not included even though it is matched by the rules,
// which means that the custom negation base set has precedence over the
// final selection set as a whole
"connect", "open", "ptrace", "mmap", "execve", "read", "syncfs"
// todo(jasondellaluce): add "accept4" once names_to_sc_set is polished on the libs side
"connect", "umount2", "open", "ptrace", "mmap", "execve", "read", "syncfs", "sched_process_exit"
});
ASSERT_NAMES_CONTAIN(selected_sc_names, expected_sc_names);
ASSERT_NAMES_EQ(selected_sc_names, expected_sc_names);
// non-empty custom base set (both positive and negative with collision)
s.config->m_base_syscalls = {"syncfs", "accept", "!accept"};
s.config->m_base_syscalls_repair = false;
s.config->m_base_syscalls_custom_set = {"syncfs", "accept", "!accept"};
result = falco::app::actions::configure_interesting_sets(s);
ASSERT_TRUE(result.success);
ASSERT_EQ(result.errstr, "");
selected_sc_names = libsinsp::events::sc_set_to_names(s.selected_sc_set);
// note: in case of collision, negation has priority, so the expected
// names are the same as the case above
ASSERT_NAMES_CONTAIN(selected_sc_names, expected_sc_names);
ASSERT_NAMES_EQ(selected_sc_names, expected_sc_names);
// non-empty custom base set (only positive)
s.config->m_base_syscalls = {"syncfs"};
s.config->m_base_syscalls_custom_set = {"syncfs"};
result = falco::app::actions::configure_interesting_sets(s);
ASSERT_TRUE(result.success);
ASSERT_EQ(result.errstr, "");
selected_sc_names = libsinsp::events::sc_set_to_names(s.selected_sc_set);
expected_sc_names = strset_t({
// note: accept is not negated anymore
"connect", "accept", "open", "ptrace", "mmap", "execve", "read", "syncfs"
"connect", "accept", "accept4", "umount2", "open", "ptrace", "mmap", "execve", "read", "syncfs", "sched_process_exit"
});
ASSERT_NAMES_CONTAIN(selected_sc_names, expected_sc_names);
ASSERT_NAMES_EQ(selected_sc_names, expected_sc_names);
// non-empty custom base set (only negative)
s.config->m_base_syscalls = {"!accept"};
s.config->m_base_syscalls_custom_set = {"!accept"};
result = falco::app::actions::configure_interesting_sets(s);
ASSERT_TRUE(result.success);
ASSERT_EQ(result.errstr, "");
selected_sc_names = libsinsp::events::sc_set_to_names(s.selected_sc_set);
expected_sc_names = unordered_set_union(
libsinsp::events::sc_set_to_names(default_base_set),
strset_t({ "connect", "open", "ptrace", "mmap", "execve", "read"}));
strset_t({ "connect", "umount2", "open", "ptrace", "mmap", "execve", "read"}));
expected_sc_names.erase("accept");
// todo(jasondellaluce): add "accept4" once names_to_sc_set is polished on the libs side
expected_sc_names.erase("accept4");
ASSERT_NAMES_CONTAIN(selected_sc_names, expected_sc_names);
ASSERT_NAMES_EQ(selected_sc_names, expected_sc_names);
// non-empty custom base set (positive, without -A)
s.options.all_events = false;
s.config->m_base_syscalls = {"read"};
s.config->m_base_syscalls_custom_set = {"read"};
result = falco::app::actions::configure_interesting_sets(s);
ASSERT_TRUE(result.success);
ASSERT_EQ(result.errstr, "");
@@ -346,7 +353,38 @@ TEST(ConfigureInterestingSets, selection_custom_base_set)
expected_sc_names = strset_t({
// note: read is both part of the custom base set and the rules set,
// but we expect the unset -A option to take precedence
"connect", "accept", "open", "ptrace", "mmap", "execve",
"connect", "accept", "accept4", "umount2", "open", "ptrace", "mmap", "execve", "sched_process_exit"
});
ASSERT_NAMES_EQ(selected_sc_names, expected_sc_names);
auto unexpected_sc_names = libsinsp::events::sc_set_to_names(libsinsp::events::io_sc_set());
ASSERT_NAMES_NOCONTAIN(selected_sc_names, unexpected_sc_names);
}
TEST(ConfigureInterestingSets, selection_custom_base_set_repair)
{
// run app action with fake engine and without the `-A` option
falco::app::state s;
s.options.all_events = false;
s.engine = mock_engine_from_filters(s_sample_filters);
// simulate empty custom set but repair option set.
// 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
// repaired. Also, given that we use some network syscalls, we expect "bind"
// to be selected event if we negate it, because repairment should have
// take precedence.
s.config->m_base_syscalls_custom_set = {"openat", "!bind"};
s.config->m_base_syscalls_repair = true;
auto result = falco::app::actions::configure_interesting_sets(s);
ASSERT_TRUE(result.success);
ASSERT_EQ(result.errstr, "");
auto selected_sc_names = libsinsp::events::sc_set_to_names(s.selected_sc_set);
auto expected_sc_names = strset_t({
// note: expecting syscalls from mock rules and `sinsp_repair_state_sc_set` enforced syscalls
"connect", "accept", "accept4", "umount2", "open", "ptrace", "mmap", "execve", "sched_process_exit", \
"bind", "socket", "clone3", "close", "setuid"
});
ASSERT_NAMES_CONTAIN(selected_sc_names, expected_sc_names);
auto unexpected_sc_names = libsinsp::events::sc_set_to_names(libsinsp::events::io_sc_set());
ASSERT_NAMES_NOCONTAIN(selected_sc_names, unexpected_sc_names);
}

View File

@@ -15,7 +15,14 @@ limitations under the License.
*/
#include <cstdlib>
#ifndef _WIN32
#include <unistd.h>
#else
#include <stdlib.h>
#include <io.h>
#define srandom srand
#define random rand
#endif
#include <string>
#include <fstream>
#include <functional>

View File

@@ -21,4 +21,4 @@ limitations under the License.
// This is the result of running "falco --list -N | sha256sum" and
// represents the fields supported by this version of Falco. It's used
// at build time to detect a changed set of fields.
#define FALCO_FIELDS_CHECKSUM "f054e066bd153f851285973bb2f628462574d4679c18e1ca5dbca0585acc8a72"
#define FALCO_FIELDS_CHECKSUM "8684342b994f61ca75a1a494e1197b86b53715c59ad60de3768d4d74ea4ba2c9"

View File

@@ -17,6 +17,7 @@ set(
FALCO_SOURCES
app/app.cpp
app/options.cpp
app/restart_handler.cpp
app/actions/helpers_generic.cpp
app/actions/helpers_inspector.cpp
app/actions/configure_interesting_sets.cpp

View File

@@ -23,7 +23,6 @@ namespace falco {
namespace app {
namespace actions {
falco::app::run_result attach_inotify_signals(falco::app::state& s);
falco::app::run_result configure_interesting_sets(falco::app::state& s);
falco::app::run_result configure_syscall_buffer_size(falco::app::state& s);
falco::app::run_result create_requested_paths(falco::app::state& s);

View File

@@ -71,21 +71,21 @@ static void select_event_set(falco::app::state& s, const libsinsp::events::set<p
}
/* DEFAULT OPTION:
* Current sinsp_state_sc_set() approach includes multiple steps:
* Current `sinsp_state_sc_set()` approach includes multiple steps:
* (1) Enforce all positive syscalls from each Falco rule
* (2) Enforce static `libsinsp` state set (non-adaptive, not conditioned by rules,
* (2) Enforce static Falco state set (non-adaptive, not conditioned by rules,
* but based on PPME event table flags indicating generic sinsp state modifications)
* -> Final set is union of (1) and (2)
*
* Fall-back if no valid positive syscalls in "base_syscalls",
* e.g. when using "base_syscalls" only for negative syscalls.
* Fall-back if no valid positive syscalls in `base_syscalls.custom_set`,
* e.g. when using `base_syscalls.custom_set` only for negative syscalls.
*/
auto base_sc_set = libsinsp::events::sinsp_state_sc_set();
/* USER OVERRIDE INPUT OPTION "base_syscalls". */
/* USER OVERRIDE INPUT OPTION `base_syscalls.custom_set` etc. */
std::unordered_set<std::string> user_positive_names = {};
std::unordered_set<std::string> user_negative_names = {};
extract_base_syscalls_names(s.config->m_base_syscalls, user_positive_names, user_negative_names);
extract_base_syscalls_names(s.config->m_base_syscalls_custom_set, user_positive_names, user_negative_names);
auto user_positive_sc_set = libsinsp::events::names_to_sc_set(user_positive_names);
auto user_negative_sc_set = libsinsp::events::names_to_sc_set(user_negative_names);
@@ -100,12 +100,31 @@ static void select_event_set(falco::app::state& s, const libsinsp::events::set<p
falco_logger::log(LOG_DEBUG, "+(" + std::to_string(user_positive_sc_set_names.size())
+ ") syscalls added (base_syscalls override): "
+ concat_set_in_order(user_positive_sc_set_names) + "\n");
auto invalid_positive_sc_set_names = unordered_set_difference(user_positive_names, user_positive_sc_set_names);
if (!invalid_positive_sc_set_names.empty())
{
falco_logger::log(LOG_WARNING, "Invalid (positive) syscall names: warning (base_syscalls override): "
+ concat_set_in_order(invalid_positive_sc_set_names));
}
}
// selected events are the union of the rules events set and the
// base events set (either the default or the user-defined one)
s.selected_sc_set = rules_sc_set.merge(base_sc_set);
/* REPLACE DEFAULT STATE, nothing else. Need to override s.selected_sc_set and have a separate logic block. */
if (s.config->m_base_syscalls_repair && user_positive_sc_set.empty())
{
/* If `base_syscalls.repair` is specified, but `base_syscalls.custom_set` is empty we are replacing
* the default `sinsp_state_sc_set()` enforcement with the alternative `sinsp_repair_state_sc_set`.
* This approach only activates additional syscalls Falco needs beyond the
* syscalls defined in each Falco rule that are absolutely necessary based
* on the current rules configuration. */
// returned set already has rules_sc_set merged
s.selected_sc_set = libsinsp::events::sinsp_repair_state_sc_set(rules_sc_set);
}
if (!user_negative_sc_set.empty())
{
/* Remove negative base_syscalls events. */
@@ -117,6 +136,12 @@ static void select_event_set(falco::app::state& s, const libsinsp::events::set<p
falco_logger::log(LOG_DEBUG, "-(" + std::to_string(user_negative_sc_set_names.size())
+ ") syscalls removed (base_syscalls override): "
+ concat_set_in_order(user_negative_sc_set_names) + "\n");
auto invalid_negative_sc_set_names = unordered_set_difference(user_negative_names, user_negative_sc_set_names);
if (!invalid_negative_sc_set_names.empty())
{
falco_logger::log(LOG_WARNING, "Invalid (negative) syscall names: warning (base_syscalls override): "
+ concat_set_in_order(invalid_negative_sc_set_names));
}
}
/* Derive the diff between the additional syscalls added via libsinsp state
@@ -150,6 +175,32 @@ static void select_event_set(falco::app::state& s, const libsinsp::events::set<p
}
}
/* If a custom set is specified (positive, negative, or both), we attempt
* to repair it if configured to do so. */
if (s.config->m_base_syscalls_repair && !s.config->m_base_syscalls_custom_set.empty())
{
/* If base_syscalls.repair is specified enforce state using `sinsp_repair_state_sc_set`.
* This approach is an alternative to the default `sinsp_state_sc_set()` state enforcement
* and only activates additional syscalls Falco needs beyond the syscalls defined in the
* Falco rules that are absolutely necessary based on the current rules configuration. */
auto selected_sc_set = s.selected_sc_set;
s.selected_sc_set = libsinsp::events::sinsp_repair_state_sc_set(s.selected_sc_set);
auto repaired_sc_set = s.selected_sc_set.diff(selected_sc_set);
if (!repaired_sc_set.empty())
{
auto repaired_sc_set_names = libsinsp::events::sc_set_to_names(repaired_sc_set);
falco_logger::log(LOG_INFO, "+(" + std::to_string(repaired_sc_set_names.size())
+ ") repaired syscalls: " + concat_set_in_order(repaired_sc_set_names) + "\n");
}
}
/* Hidden safety enforcement for `base_syscalls.custom_set` user
* input override option (but keep as general safety enforcement)
* -> sched_process_exit trace point activation (procexit event)
* is necessary for continuous state engine cleanup,
* else memory would grow rapidly and linearly over time. */
s.selected_sc_set.insert(ppm_sc_code::PPM_SC_SCHED_PROCESS_EXIT);
if (!s.selected_sc_set.empty())
{
auto selected_sc_set_names = libsinsp::events::sc_set_to_names(s.selected_sc_set);
@@ -159,16 +210,6 @@ static void select_event_set(falco::app::state& s, const libsinsp::events::set<p
}
}
static void select_kernel_tracepoint_set(falco::app::state& s)
{
/* Kernel tracepoints activation
* Activate all tracepoints except `sched_switch` tracepoint since it
* is highly noisy and not so useful
* for our state/events enrichment. */
s.selected_tp_set = libsinsp::events::sinsp_state_tp_set();
s.selected_tp_set.remove(ppm_tp_code::SCHED_SWITCH);
}
falco::app::run_result falco::app::actions::configure_interesting_sets(falco::app::state& s)
{
if (s.engine == nullptr || s.config == nullptr)
@@ -177,8 +218,7 @@ falco::app::run_result falco::app::actions::configure_interesting_sets(falco::ap
}
s.selected_sc_set.clear();
s.selected_tp_set.clear();
/* note: the set of events is the richest source of truth about
* the events generable by an inspector, because they also carry information
* about events that are old, unused, internal, and so on. As such, the
@@ -190,6 +230,5 @@ falco::app::run_result falco::app::actions::configure_interesting_sets(falco::ap
auto rules_sc_set = s.engine->sc_codes_for_ruleset(falco_common::syscall_source);
select_event_set(s, rules_sc_set);
check_for_rules_unsupported_events(s, rules_sc_set);
select_kernel_tracepoint_set(s);
return run_result::ok();
}

View File

@@ -16,23 +16,16 @@ limitations under the License.
#include <functional>
#include <string.h>
#include <signal.h>
#include <sys/inotify.h>
#include <fcntl.h>
#include "actions.h"
#include "../app.h"
#include "../signals.h"
#include <signal.h>
using namespace falco::app;
using namespace falco::app::actions;
// This is initially set to a dummy application. When
// create_signal_handlers is called, it will be rebound to the
// provided application, and in unregister_signal_handlers it will be
// rebound back to the dummy application.
static int inot_fd;
static std::shared_ptr<falco::app::restart_handler> s_restarter;
static void terminate_signal_handler(int signal)
{
@@ -46,7 +39,10 @@ static void reopen_outputs_signal_handler(int signal)
static void restart_signal_handler(int signal)
{
falco::app::g_restart_signal.trigger();
if (s_restarter != nullptr)
{
s_restarter->trigger();
}
}
bool create_handler(int sig, void (*func)(int), run_result &ret)
@@ -71,6 +67,12 @@ bool create_handler(int sig, void (*func)(int), run_result &ret)
falco::app::run_result falco::app::actions::create_signal_handlers(falco::app::state& s)
{
if (s.options.dry_run)
{
falco_logger::log(LOG_DEBUG, "Skipping signal handlers creation in dry-run\n");
return run_result::ok();
}
falco::app::g_terminate_signal.reset();
falco::app::g_restart_signal.reset();
falco::app::g_reopen_outputs_signal.reset();
@@ -88,87 +90,80 @@ falco::app::run_result falco::app::actions::create_signal_handlers(falco::app::s
! create_handler(SIGUSR1, ::reopen_outputs_signal_handler, ret) ||
! create_handler(SIGHUP, ::restart_signal_handler, ret))
{
// we use the if just to make sure we return at the first failed statement
return ret;
}
return ret;
}
falco::app::run_result falco::app::actions::attach_inotify_signals(falco::app::state& s)
{
if (s.config->m_watch_config_files)
falco::app::restart_handler::watch_list_t files_to_watch;
falco::app::restart_handler::watch_list_t dirs_to_watch;
if (s.config->m_watch_config_files)
{
inot_fd = inotify_init();
if (inot_fd == -1)
{
return run_result::fatal("Could not create inotify handler");
}
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sa.sa_handler = restart_signal_handler;
if (sigaction(SIGIO, &sa, NULL) == -1)
{
return run_result::fatal("Failed to link SIGIO to inotify handler");
}
/* Set owner process that is to receive "I/O possible" signal */
if (fcntl(inot_fd, F_SETOWN, getpid()) == -1)
{
return run_result::fatal("Failed to setting owner on inotify handler");
}
/*
* Enable "I/O possible" signaling and make I/O nonblocking
* for file descriptor
*/
int flags = fcntl(inot_fd, F_GETFL);
if (fcntl(inot_fd, F_SETFL, flags | O_ASYNC | O_NONBLOCK) == -1)
{
return run_result::fatal("Failed to setting flags on inotify handler");
}
// Watch conf file
int wd = inotify_add_watch(inot_fd, s.options.conf_filename.c_str(), IN_CLOSE_WRITE);
if (wd == -1)
{
return run_result::fatal("Failed to watch conf file");
}
falco_logger::log(LOG_DEBUG, "Watching " + s.options.conf_filename +"\n");
// Watch rules files
for (const auto &rule : s.config->m_loaded_rules_filenames)
{
wd = inotify_add_watch(inot_fd, rule.c_str(), IN_CLOSE_WRITE | IN_ONESHOT);
if (wd == -1)
{
return run_result::fatal("Failed to watch rule file: " + rule);
}
falco_logger::log(LOG_DEBUG, "Watching " + rule +"\n");
}
// Watch specified rules folders, if any:
// any newly created/removed file within the folder
// will trigger a Falco restart.
for (const auto &fld : s.config->m_loaded_rules_folders)
{
// For folders, we watch if any file is created or destroyed within
wd = inotify_add_watch(inot_fd, fld.c_str(), IN_CREATE | IN_DELETE | IN_ONESHOT);
if (wd == -1)
{
return run_result::fatal("Failed to watch rule folder: " + fld);
}
falco_logger::log(LOG_DEBUG, "Watching " + fld +" folder\n");
}
files_to_watch.push_back(s.options.conf_filename);
files_to_watch.insert(
files_to_watch.end(),
s.config->m_loaded_rules_filenames.begin(),
s.config->m_loaded_rules_filenames.end());
dirs_to_watch.insert(
dirs_to_watch.end(),
s.config->m_loaded_rules_folders.begin(),
s.config->m_loaded_rules_folders.end());
}
return run_result::ok();
s.restarter = std::make_shared<falco::app::restart_handler>([&s]{
bool tmp = false;
bool success = false;
std::string err;
falco::app::state tmp_state(s.cmdline, s.options);
tmp_state.options.dry_run = true;
try
{
success = falco::app::run(tmp_state, tmp, err);
}
catch (std::exception& e)
{
err = e.what();
}
catch (...)
{
err = "unknown error";
}
if (!success && s.outputs != nullptr)
{
std::string rule = "Falco internal: hot restart failure";
std::string msg = rule + ": " + err;
std::map<std::string, std::string> o = {};
auto now = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
s.outputs->handle_msg(now, falco_common::PRIORITY_CRITICAL, msg, rule, o);
}
return success;
}, files_to_watch, dirs_to_watch);
ret = run_result::ok();
ret.success = s.restarter->start(ret.errstr);
ret.proceed = ret.success;
if (ret.success)
{
s_restarter = s.restarter;
}
return ret;
}
falco::app::run_result falco::app::actions::unregister_signal_handlers(falco::app::state& s)
{
if (s.options.dry_run)
{
falco_logger::log(LOG_DEBUG, "Skipping unregistering signal handlers in dry-run\n");
return run_result::ok();
}
s_restarter = nullptr;
if (s.restarter != nullptr)
{
s.restarter->stop();
}
run_result ret;
close(inot_fd);
if(! create_handler(SIGINT, SIG_DFL, ret) ||
! create_handler(SIGTERM, SIG_DFL, ret) ||
! create_handler(SIGUSR1, SIG_DFL, ret) ||

View File

@@ -27,6 +27,12 @@ static bool s_daemonized = false;
falco::app::run_result falco::app::actions::daemonize(falco::app::state& s)
{
if (s.options.dry_run)
{
falco_logger::log(LOG_DEBUG, "Skipping daemonizing in dry-run\n");
return run_result::ok();
}
// If daemonizing, do it here so any init errors will
// be returned in the foreground process.
if (s.options.daemon && !s_daemonized) {

View File

@@ -81,7 +81,7 @@ falco::app::run_result falco::app::actions::open_live_inspector(
{
falco_logger::log(LOG_INFO, "Opening capture with modern BPF probe.");
falco_logger::log(LOG_INFO, "One ring buffer every '" + std::to_string(s.config->m_cpus_for_each_syscall_buffer) + "' CPUs.");
inspector->open_modern_bpf(s.syscall_buffer_bytes_size, s.config->m_cpus_for_each_syscall_buffer, true, s.selected_sc_set, s.selected_tp_set);
inspector->open_modern_bpf(s.syscall_buffer_bytes_size, s.config->m_cpus_for_each_syscall_buffer, true, s.selected_sc_set);
}
else if(getenv(FALCO_BPF_ENV_VARIABLE) != NULL) /* BPF engine. */
{
@@ -99,14 +99,14 @@ falco::app::run_result falco::app::actions::open_live_inspector(
bpf_probe_path = full_path;
}
falco_logger::log(LOG_INFO, "Opening capture with BPF probe. BPF probe path: " + std::string(bpf_probe_path));
inspector->open_bpf(bpf_probe_path, s.syscall_buffer_bytes_size, s.selected_sc_set, s.selected_tp_set);
inspector->open_bpf(bpf_probe_path, s.syscall_buffer_bytes_size, s.selected_sc_set);
}
else /* Kernel module (default). */
{
try
{
falco_logger::log(LOG_INFO, "Opening capture with Kernel module");
inspector->open_kmod(s.syscall_buffer_bytes_size, s.selected_sc_set, s.selected_tp_set);
inspector->open_kmod(s.syscall_buffer_bytes_size, s.selected_sc_set);
}
catch(sinsp_exception &e)
{
@@ -116,7 +116,7 @@ falco::app::run_result falco::app::actions::open_live_inspector(
{
falco_logger::log(LOG_ERR, "Unable to load the driver\n");
}
inspector->open_kmod(s.syscall_buffer_bytes_size, s.selected_sc_set, s.selected_tp_set);
inspector->open_kmod(s.syscall_buffer_bytes_size, s.selected_sc_set);
}
}
}

View File

@@ -35,6 +35,12 @@ falco::app::run_result falco::app::actions::init_clients(falco::app::state& s)
falco_logger::log(LOG_DEBUG, "Setting metadata download watch frequency to " + std::to_string(s.config->m_metadata_download_watch_freq_sec) + " seconds\n");
inspector->set_metadata_download_params(s.config->m_metadata_download_max_mb * 1024 * 1024, s.config->m_metadata_download_chunk_wait_us, s.config->m_metadata_download_watch_freq_sec);
if (s.options.dry_run)
{
falco_logger::log(LOG_DEBUG, "Skipping clients initialization in dry-run\n");
return run_result::ok();
}
//
// Run k8s, if required
//

View File

@@ -48,6 +48,12 @@ static void init_syscall_inspector(falco::app::state& s, std::shared_ptr<sinsp>
inspector->set_snaplen(s.options.snaplen);
}
if (s.config->m_syscall_drop_failed_exit)
{
falco_logger::log(LOG_INFO, "Failed syscall exit events are dropped in the kernel driver\n");
inspector->set_dropfailed(true);
}
inspector->set_hostname_and_port_resolution_mode(false);
}

View File

@@ -49,6 +49,12 @@ falco::app::run_result falco::app::actions::init_outputs(falco::app::state& s)
hostname = c_hostname;
}
if (s.options.dry_run)
{
falco_logger::log(LOG_DEBUG, "Skipping daemonizing in dry-run\n");
return run_result::ok();
}
s.outputs.reset(new falco_outputs(
s.engine,
s.config->m_outputs,

View File

@@ -208,8 +208,9 @@ static falco::app::run_result do_inspect(
}
else if(falco::app::g_restart_signal.triggered())
{
falco::app::g_restart_signal.handle([&](){
falco::app::g_restart_signal.handle([&s](){
falco_logger::log(LOG_INFO, "SIGHUP received, restarting...\n");
s.restart.store(true);
});
break;
}
@@ -410,6 +411,12 @@ falco::app::run_result falco::app::actions::process_events(falco::app::state& s)
// Initialize stats writer
auto statsw = init_stats_writer(s.options);
if (s.options.dry_run)
{
falco_logger::log(LOG_DEBUG, "Skipping event processing in dry-run\n");
return run_result::ok();
}
// Start processing events
if(s.is_capture_mode())
{
@@ -487,7 +494,7 @@ falco::app::run_result falco::app::actions::process_events(falco::app::state& s)
// wait for event processing to terminate for all sources
// if a thread terminates with an error, we trigger the app termination
// to force all other event streams to termiante too.
// to force all other event streams to terminate too.
// We accomulate the errors in a single run_result.
size_t closed_count = 0;
while (closed_count < ctxs.size())

View File

@@ -29,6 +29,12 @@ falco::app::run_result falco::app::actions::start_grpc_server(falco::app::state&
// gRPC server
if(s.config->m_grpc_enabled)
{
if (s.options.dry_run)
{
falco_logger::log(LOG_DEBUG, "Skipping starting gRPC server in dry-run\n");
return run_result::ok();
}
falco_logger::log(LOG_INFO, "gRPC server threadiness equals to " + std::to_string(s.config->m_grpc_threadiness) + "\n");
// TODO(fntlnz,leodido): when we want to spawn multiple threads we need to have a queue per thread, or implement
// different queuing mechanisms, round robin, fanout? What we want to achieve?
@@ -51,10 +57,19 @@ falco::app::run_result falco::app::actions::start_grpc_server(falco::app::state&
falco::app::run_result falco::app::actions::stop_grpc_server(falco::app::state& s)
{
#ifndef MINIMAL_BUILD
if(s.grpc_server_thread.joinable())
if(s.config->m_grpc_enabled)
{
s.grpc_server.shutdown();
s.grpc_server_thread.join();
if (s.options.dry_run)
{
falco_logger::log(LOG_DEBUG, "Skipping stopping gRPC server in dry-run\n");
return run_result::ok();
}
if(s.grpc_server_thread.joinable())
{
s.grpc_server.shutdown();
s.grpc_server_thread.join();
}
}
#endif
return run_result::ok();

View File

@@ -28,6 +28,12 @@ falco::app::run_result falco::app::actions::start_webserver(falco::app::state& s
#ifndef MINIMAL_BUILD
if(!s.is_capture_mode() && s.config->m_webserver_enabled)
{
if (s.options.dry_run)
{
falco_logger::log(LOG_DEBUG, "Skipping starting webserver in dry-run\n");
return run_result::ok();
}
std::string ssl_option = (s.config->m_webserver_ssl_enabled ? " (SSL)" : "");
falco_logger::log(LOG_INFO, "Starting health webserver with threadiness "
+ std::to_string(s.config->m_webserver_threadiness)
@@ -50,8 +56,14 @@ falco::app::run_result falco::app::actions::start_webserver(falco::app::state& s
falco::app::run_result falco::app::actions::stop_webserver(falco::app::state& s)
{
#ifndef MINIMAL_BUILD
if(!s.is_capture_mode())
if(!s.is_capture_mode() && s.config->m_webserver_enabled)
{
if (s.options.dry_run)
{
falco_logger::log(LOG_DEBUG, "Skipping stopping webserver in dry-run\n");
return run_result::ok();
}
s.webserver.stop();
}
#endif

View File

@@ -40,7 +40,11 @@ bool falco::app::run(int argc, char** argv, bool& restart, std::string& errstr)
}
s.cmdline += *arg;
}
return falco::app::run(s, restart, errstr);
}
bool falco::app::run(falco::app::state& s, bool& restart, std::string& errstr)
{
// The order here is the order in which the methods will be
// called. Before changing the order, ensure that all
// dependencies are honored (e.g. don't process events before
@@ -64,11 +68,10 @@ bool falco::app::run(int argc, char** argv, bool& restart, std::string& errstr)
falco::app::actions::validate_rules_files,
falco::app::actions::load_rules_files,
falco::app::actions::print_support,
falco::app::actions::init_outputs,
falco::app::actions::create_signal_handlers,
falco::app::actions::attach_inotify_signals,
falco::app::actions::create_requested_paths,
falco::app::actions::daemonize,
falco::app::actions::init_outputs,
falco::app::actions::init_clients,
falco::app::actions::configure_interesting_sets,
falco::app::actions::configure_syscall_buffer_size,
@@ -104,7 +107,7 @@ bool falco::app::run(int argc, char** argv, bool& restart, std::string& errstr)
errstr = res.errstr;
}
restart = falco::app::g_restart_signal.triggered();
restart = s.restart;
return res.success;
}

View File

@@ -16,12 +16,15 @@ limitations under the License.
#pragma once
#include "state.h"
#include <string>
namespace falco {
namespace app {
bool run(int argc, char** argv, bool& restart, std::string& errstr);
bool run(falco::app::state& s, bool& restart, std::string& errstr);
}; // namespace app
}; // namespace falco

View File

@@ -18,6 +18,8 @@ limitations under the License.
#include "../configuration.h"
#include "config_falco.h"
#include <cxxopts.hpp>
#include <fstream>
namespace falco {
@@ -34,10 +36,8 @@ options::options()
list_plugins(false),
list_syscall_events(false),
markdown(false),
modern_bpf(false),
m_cmdline_opts("falco", "Falco - Cloud Native Runtime Security")
modern_bpf(false)
{
define();
}
options::~options()
@@ -46,8 +46,13 @@ options::~options()
bool options::parse(int argc, char **argv, std::string &errstr)
{
cxxopts::Options opts("falco", "Falco - Cloud Native Runtime Security");
define(opts);
m_usage_str = opts.help();
cxxopts::ParseResult m_cmdline_parsed;
try {
m_cmdline_parsed = m_cmdline_opts.parse(argc, argv);
m_cmdline_parsed = opts.parse(argc, argv);
}
catch (std::exception &e)
{
@@ -145,14 +150,14 @@ bool options::parse(int argc, char **argv, std::string &errstr)
return true;
}
std::string options::usage()
const std::string& options::usage()
{
return m_cmdline_opts.help();
return m_usage_str;
}
void options::define()
void options::define(cxxopts::Options& opts)
{
m_cmdline_opts.add_options()
opts.add_options()
("h,help", "Print this page", cxxopts::value(help)->default_value("false"))
#ifdef BUILD_TYPE_RELEASE
("c", "Configuration file. If not specified uses " FALCO_INSTALL_CONF_FILE ".", cxxopts::value(conf_filename), "<path>")
@@ -165,6 +170,7 @@ void options::define()
("d,daemon", "Run as a daemon.", cxxopts::value(daemon)->default_value("false"))
("disable-cri-async", "Disable asynchronous CRI metadata fetching. This is useful to let the input event wait for the container metadata fetch to finish before moving forward. Async fetching, in some environments leads to empty fields for container metadata when the fetch is not fast enough to be completed asynchronously. This can have a performance penalty on your environment depending on the number of containers and the frequency at which they are created/started/stopped.", cxxopts::value(disable_cri_async)->default_value("false"))
("disable-source", "Disable a specific event source. By default, all loaded sources get enabled. Available sources are 'syscall' and all sources defined by loaded plugins supporting the event sourcing capability. This option can be passed multiple times. This has no offect when reading events from a trace file. Can not disable all event sources. Can not be mixed with --enable-source.", cxxopts::value(disable_sources), "<event_source>")
("dry-run", "Run Falco without proceesing events. Can be useful for checking that the configuration and rules do not have any errors.", cxxopts::value(dry_run)->default_value("false"))
("D", "Disable any rules with names having the substring <substring>. This option can be passed multiple times. Can not be mixed with -t.", cxxopts::value(disabled_rule_substrings), "<substring>")
("e", "Read the events from a trace file <events_file> in .scap format instead of tapping into live.", cxxopts::value(trace_filename), "<events_file>")
("enable-source", "Enable a specific event source. If used, all loaded sources get disabled by default and only the ones passed with this option get enabled. Available sources are 'syscall' and all sources defined by loaded plugins supporting the event sourcing capability. This option can be passed multiple times. This has no offect when reading events from a trace file. Can not be mixed with --disable-source.", cxxopts::value(enable_sources), "<event_source>")
@@ -214,7 +220,7 @@ void options::define()
("page-size", "Print the system page size (may help you to choose the right syscall ring-buffer size).", cxxopts::value(print_page_size)->default_value("false"));
m_cmdline_opts.set_width(140);
opts.set_width(140);
}
}; // namespace app

View File

@@ -18,12 +18,12 @@ limitations under the License.
#include <event.h>
#include <cxxopts.hpp>
#include <string>
#include <vector>
#include <set>
namespace cxxopts { class Options; };
namespace falco {
namespace app {
@@ -84,15 +84,15 @@ public:
bool print_version_info;
bool print_page_size;
bool modern_bpf;
bool dry_run;
bool parse(int argc, char **argv, std::string &errstr);
std::string usage();
private:
void define();
const std::string& usage();
cxxopts::Options m_cmdline_opts;
cxxopts::ParseResult m_cmdline_parsed;
private:
void define(cxxopts::Options& opts);
std::string m_usage_str;
};
}; // namespace application

View File

@@ -0,0 +1,204 @@
/*
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 "restart_handler.h"
#include "signals.h"
#include "../logger.h"
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/inotify.h>
#include <sys/select.h>
#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 30
#include <sys/syscall.h>
#define gettid() syscall(SYS_gettid)
#endif
falco::app::restart_handler::~restart_handler()
{
close(m_inotify_fd);
stop();
}
void falco::app::restart_handler::trigger()
{
m_forced.store(true, std::memory_order_release);
}
bool falco::app::restart_handler::start(std::string& err)
{
m_inotify_fd = inotify_init();
if (m_inotify_fd < 0)
{
err = "could not initialize inotify handler";
return false;
}
for (const auto& f : m_watched_files)
{
auto wd = inotify_add_watch(m_inotify_fd, f.c_str(), IN_CLOSE_WRITE);
if (wd < 0)
{
err = "could not watch file: " + f;
return false;
}
falco_logger::log(LOG_DEBUG, "Watching file '" + f +"'\n");
}
for (const auto &f : m_watched_dirs)
{
auto wd = inotify_add_watch(m_inotify_fd, f.c_str(), IN_CREATE | IN_DELETE);
if (wd < 0)
{
err = "could not watch directory: " + f;
return false;
}
falco_logger::log(LOG_DEBUG, "Watching directory '" + f +"'\n");
}
// launch the watcher thread
m_watcher = std::thread(&falco::app::restart_handler::watcher_loop, this);
return true;
}
void falco::app::restart_handler::stop()
{
m_stop.store(true, std::memory_order_release);
if (m_watcher.joinable())
{
m_watcher.join();
}
}
void falco::app::restart_handler::watcher_loop() noexcept
{
if (fcntl(m_inotify_fd, F_SETOWN, gettid()) < 0)
{
// an error occurred, we can't recover
// todo(jasondellaluce): should we terminate the process?
falco_logger::log(LOG_ERR, "Failed owning inotify handler, shutting down watcher...");
return;
}
fd_set set;
bool forced = false;
bool should_check = false;
bool should_restart = false;
struct timeval timeout;
uint8_t buf[(10 * (sizeof(struct inotify_event) + NAME_MAX + 1))];
while (!m_stop.load(std::memory_order_acquire))
{
// wait for inotify events with a certain timeout.
// Note, we'll run through select even before performing a dry-run,
// so that we can dismiss in case we have to debounce rapid
// subsequent events.
timeout.tv_sec = 0;
timeout.tv_usec = 100000;
FD_ZERO(&set);
FD_SET(m_inotify_fd, &set);
auto rv = select(m_inotify_fd + 1, &set, NULL, NULL, &timeout);
if (rv < 0)
{
// an error occurred, we can't recover
// todo(jasondellaluce): should we terminate the process?
falco_logger::log(LOG_ERR, "Failed select with inotify handler, shutting down watcher...");
return;
}
// check if there's been a forced restart request
forced = m_forced.load(std::memory_order_acquire);
m_forced.store(false, std::memory_order_release);
// no new watch event is received during the timeout
if (rv == 0 && !forced)
{
// perform a dry run. In case no error occurs, we loop back
// to the select in order to debounce new inotify events before
// actually triggering a restart.
if (should_check)
{
should_check = false;
should_restart = m_on_check();
continue;
}
// if the previous dry run was successful, and no new
// inotify events have been received during the dry run,
// then we trigger the restarting signal and quit.
// note: quitting is a time optimization, the thread
// will be forced to quit anyways later by the Falco app, but
// at least we don't make users wait for the timeout.
if (should_restart)
{
should_restart = false;
// todo(jasondellaluce): make this a callback too maybe?
g_restart_signal.trigger();
return;
}
// let's go back to the select
continue;
}
// at this point, we either received a new inotify event or a forced
// restart. If this happened during a dry run (even if the dry run
// was successful), or during a timeout wait since the last successful
// dry run before a restart, we dismiss the restart attempt and
// perform an additional dry-run for safety purposes (the new inotify
// events may be related to bad config/rules files changes).
should_restart = false;
should_check = false;
// if there's date on the inotify fd, consume it
// (even if there is a forced request too)
if (rv > 0)
{
// note: if available data is less than buffer size, this should
// return n > 0 but not filling the buffer. If available data is
// more than buffer size, we will loop back to select and behave
// like we debounced an event.
auto n = read(m_inotify_fd, buf, sizeof(buf));
if (n < 0)
{
// an error occurred, we can't recover
// todo(jasondellaluce): should we terminate the process?
falco_logger::log(LOG_ERR, "Failed read with inotify handler, shutting down watcher...");
return;
}
// this is an odd case, but if we got here with
// no read data, and no forced request, we get back
// looping in the select. This can likely happen if
// there's data in the inotify fd but the first read
// returned no bytes. Likely we'll get back here at the
// next select call.
else if (n == 0)
{
// we still proceed in case the request was forced
if (!forced)
{
continue;
}
}
}
// we consumed the new inotify events or we received a forced
// restart request, so we'll perform a dry run after the
// next timeout.
should_check = true;
}
}

View File

@@ -0,0 +1,81 @@
/*
Copyright (C) 2023 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#pragma once
#include <thread>
#include <atomic>
#include <vector>
#include <string>
#include <functional>
namespace falco
{
namespace app
{
/**
* @brief A thread-safe helper for handling hot-reload application restarts.
*/
class restart_handler
{
public:
/**
* @brief A function that performs safety checks before confirming
* a triggered application restart. Returns true if the application
* can safely be restarted.
*/
using on_check_t = std::function<bool()>;
/**
* @brief A list of files or directories paths to watch.
*/
using watch_list_t = std::vector<std::string>;
restart_handler(
on_check_t on_check,
const watch_list_t& watch_files = {},
const watch_list_t& watch_dirs = {})
: m_inotify_fd(-1),
m_stop(false),
m_forced(false),
m_on_check(on_check),
m_watched_dirs(watch_dirs),
m_watched_files(watch_files) { }
virtual ~restart_handler();
restart_handler(restart_handler&&) = default;
restart_handler& operator = (restart_handler&&) = default;
restart_handler(const restart_handler&) = delete;
restart_handler& operator = (const restart_handler&) = delete;
bool start(std::string& err);
void stop();
void trigger();
private:
void watcher_loop() noexcept;
int m_inotify_fd;
std::thread m_watcher;
std::atomic<bool> m_stop;
std::atomic<bool> m_forced;
on_check_t m_on_check;
watch_list_t m_watched_dirs;
watch_list_t m_watched_files;
};
}; // namespace app
}; // namespace falco

View File

@@ -19,6 +19,7 @@ limitations under the License.
#include "indexed_vector.h"
#include "options.h"
#include "restart_handler.h"
#include "../configuration.h"
#include "../stats_writer.h"
#ifndef MINIMAL_BUILD
@@ -30,6 +31,7 @@ limitations under the License.
#include <string>
#include <memory>
#include <atomic>
#include <unordered_set>
namespace falco {
@@ -59,19 +61,27 @@ struct state
};
state():
restart(false),
loaded_sources(),
enabled_sources(),
source_infos(),
plugin_configs(),
selected_sc_set(),
selected_tp_set(),
syscall_buffer_bytes_size(DEFAULT_DRIVER_BUFFER_BYTES_DIM)
{
config = std::make_shared<falco_configuration>();
engine = std::make_shared<falco_engine>();
offline_inspector = std::make_shared<sinsp>();
outputs = nullptr;
restarter = nullptr;
}
state(const std::string& cmd, const falco::app::options& opts): state()
{
cmdline = cmd;
options = opts;
}
~state() = default;
state(state&&) = default;
state& operator = (state&&) = default;
@@ -80,6 +90,8 @@ struct state
std::string cmdline;
falco::app::options options;
std::atomic<bool> restart;
std::shared_ptr<falco_configuration> config;
std::shared_ptr<falco_outputs> outputs;
@@ -108,12 +120,12 @@ struct state
// Set of syscalls we want the driver to capture
libsinsp::events::set<ppm_sc_code> selected_sc_set;
// Set of tracepoints we want the driver to capture
libsinsp::events::set<ppm_tp_code> selected_tp_set;
// Dimension of the syscall buffer in bytes.
uint64_t syscall_buffer_bytes_size;
// Helper responsible for watching of handling hot application restarts
std::shared_ptr<restart_handler> restarter;
#ifndef MINIMAL_BUILD
falco::grpc::server grpc_server;
std::thread grpc_server_thread;

View File

@@ -14,6 +14,8 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
#pragma once
#include <mutex>
#include <atomic>
#include <functional>

View File

@@ -57,7 +57,8 @@ falco_configuration::falco_configuration():
m_metadata_download_chunk_wait_us(1000),
m_metadata_download_watch_freq_sec(1),
m_syscall_buf_size_preset(4),
m_cpus_for_each_syscall_buffer(2)
m_cpus_for_each_syscall_buffer(2),
m_syscall_drop_failed_exit(false)
{
}
@@ -177,6 +178,22 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h
user_agent = config.get_scalar<std::string>("http_output.user_agent","falcosecurity/falco");
http_output.options["user_agent"] = user_agent;
bool insecure;
insecure = config.get_scalar<bool>("http_output.insecure", false);
http_output.options["insecure"] = insecure? std::string("true") : std::string("false");
std::string ca_cert;
ca_cert = config.get_scalar<std::string>("http_output.ca_cert", "");
http_output.options["ca_cert"] = ca_cert;
std::string ca_bundle;
ca_bundle = config.get_scalar<std::string>("http_output.ca_bundle", "");
http_output.options["ca_bundle"] = ca_bundle;
std::string ca_path;
ca_path = config.get_scalar<std::string>("http_output.ca_path", "/etc/ssl/certs");
http_output.options["ca_path"] = ca_path;
m_outputs.push_back(http_output);
}
@@ -313,8 +330,11 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h
m_cpus_for_each_syscall_buffer = config.get_scalar<uint16_t>("modern_bpf.cpus_for_each_syscall_buffer", 2);
m_base_syscalls.clear();
config.get_sequence<std::unordered_set<std::string>>(m_base_syscalls, std::string("base_syscalls"));
m_syscall_drop_failed_exit = config.get_scalar<bool>("syscall_drop_failed_exit", false);
m_base_syscalls_custom_set.clear();
config.get_sequence<std::unordered_set<std::string>>(m_base_syscalls_custom_set, std::string("base_syscalls.custom_set"));
m_base_syscalls_repair = config.get_scalar<bool>("base_syscalls.repair", false);
std::set<std::string> load_plugins;

View File

@@ -106,8 +106,11 @@ public:
// Number of CPUs associated with a single ring buffer.
uint16_t m_cpus_for_each_syscall_buffer;
bool m_syscall_drop_failed_exit;
// User supplied base_syscalls, overrides any Falco state engine enforcement.
std::unordered_set<std::string> m_base_syscalls;
std::unordered_set<std::string> m_base_syscalls_custom_set;
bool m_base_syscalls_repair;
std::vector<plugin_config> m_plugins;

View File

@@ -34,15 +34,58 @@ void falco::outputs::output_http::output(const message *msg)
} else {
slist1 = curl_slist_append(slist1, "Content-Type: text/plain");
}
res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
curl_easy_setopt(curl, CURLOPT_URL, m_oc.options["url"].c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, msg->msg.c_str());
curl_easy_setopt(curl, CURLOPT_USERAGENT, m_oc.options["user_agent"].c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, -1L);
if(res == CURLE_OK)
{
res = curl_easy_setopt(curl, CURLOPT_URL, m_oc.options["url"].c_str());
}
if(res == CURLE_OK)
{
res = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, msg->msg.c_str());
}
if(res == CURLE_OK)
{
res = curl_easy_setopt(curl, CURLOPT_USERAGENT, m_oc.options["user_agent"].c_str());
}
res = curl_easy_perform(curl);
if(res == CURLE_OK)
{
res = curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, -1L);
}
if(res == CURLE_OK)
{
if(m_oc.options["insecure"] == std::string("true"))
{
res = curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER, 0L);
if(res == CURLE_OK)
{
res = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
}
}
}
if(res == CURLE_OK)
{
if (!m_oc.options["ca_cert"].empty())
{
res = curl_easy_setopt(curl, CURLOPT_CAINFO, m_oc.options["ca_cert"].c_str());
}else if(!m_oc.options["ca_bundle"].empty())
{
res = curl_easy_setopt(curl, CURLOPT_CAINFO, m_oc.options["ca_bundle"].c_str());
}else{
res = curl_easy_setopt(curl, CURLOPT_CAPATH, m_oc.options["ca_path"].c_str());
}
}
if(res == CURLE_OK)
{
res = curl_easy_perform(curl);
}
if(res != CURLE_OK)
{

View File

@@ -26,7 +26,12 @@ limitations under the License.
class falco_webserver
{
public:
falco_webserver() = default;
virtual ~falco_webserver();
falco_webserver(falco_webserver&&) = default;
falco_webserver& operator = (falco_webserver&&) = default;
falco_webserver(const falco_webserver&) = delete;
falco_webserver& operator = (const falco_webserver&) = delete;
virtual void start(
const std::shared_ptr<sinsp>& inspector,
uint32_t threadiness,