Compare commits

..

3 Commits

Author SHA1 Message Date
Andrea Terzolo
7e8bf42ff9 update: address some review comments
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
Co-authored-by: Leonardo Grasso <me@leonardograsso.com>
Co-authored-by: Melissa Kilby <melissa.kilby.oss@gmail.com>
2022-09-20 15:52:12 +00:00
Andrea Terzolo
a151418270 update(syscall_buffer_size): don't crash in case of getpagesize error
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
Co-authored-by: Federico Di Pierro <nierro92@gmail.com>
2022-09-20 15:16:29 +00:00
Andrea Terzolo
69623e9b93 new: configure syscall buffer dimension from Falco
Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
2022-09-20 12:14:45 +00:00
17 changed files with 194 additions and 59 deletions

View File

@@ -25,19 +25,4 @@ do
ln -s "$i" "/usr/src/$base"
done
if [ -n "$HOST_ROOT" ] && [ "$HOST_ROOT" != "/" ]; then
echo "* Setting up /lib/modules links from host"
ln -s /lib/modules $HOST_ROOT/lib/modules
# If HOST_ROOT is set, but HOST_ROOT/proc does not exist
# link real /proc to HOST_ROOT/proc, so that Falco can run gracefully.
# This is mostly useful when dealing with an hypervisor, like aws Fargate,
# where the container running Falco does not need to bind-mount the host proc volume,
# and its /proc already sees all task processes because it shares the same namespace.
if [ ! -d "$HOST_ROOT/proc" ]; then
echo "* Setting up /proc links from host"
ln -s "/proc" "$HOST_ROOT/proc"
fi
fi
/usr/bin/falco-driver-loader "$@"
/usr/bin/falco-driver-loader "$@"

View File

@@ -103,7 +103,8 @@ RUN sed -e 's/time_format_iso_8601: false/time_format_iso_8601: true/' < /etc/fa
# Some base images have an empty /lib/modules by default
# If it's not empty, docker build will fail instead of
# silently overwriting the existing directory
RUN rm -df /lib/modules
RUN rm -df /lib/modules \
&& ln -s $HOST_ROOT/lib/modules /lib/modules
# debian:stable head contains binutils 2.31, which generates
# binaries that are incompatible with kernels < 4.16. So manually

View File

@@ -30,19 +30,4 @@ if [[ -z "${SKIP_DRIVER_LOADER}" ]]; then
/usr/bin/falco-driver-loader
fi
if [ -n "$HOST_ROOT" ] && [ "$HOST_ROOT" != "/" ]; then
echo "* Setting up /lib/modules links from host"
ln -s /lib/modules $HOST_ROOT/lib/modules
# If HOST_ROOT is set, but HOST_ROOT/proc does not exist
# link real /proc to HOST_ROOT/proc, so that Falco can run gracefully.
# This is mostly useful when dealing with an hypervisor, like aws Fargate,
# where the container running Falco does not need to bind-mount the host proc volume,
# and its /proc already sees all task processes because it shares the same namespace.
if [ ! -d "$HOST_ROOT/proc" ]; then
echo "* Setting up /proc links from host"
ln -s "/proc" "$HOST_ROOT/proc"
fi
fi
exec "$@"
exec "$@"

View File

@@ -96,7 +96,8 @@ RUN rm -rf /usr/bin/clang \
# Some base images have an empty /lib/modules by default
# If it's not empty, docker build will fail instead of
# silently overwriting the existing directory
RUN rm -df /lib/modules
RUN rm -df /lib/modules \
&& ln -s $HOST_ROOT/lib/modules /lib/modules
ADD falco-${FALCO_VERSION}-*.deb /
RUN dpkg -i /falco-${FALCO_VERSION}-$(uname -m).deb

View File

@@ -31,19 +31,4 @@ if [[ -z "${SKIP_DRIVER_LOADER}" ]]; then
/usr/bin/falco-driver-loader
fi
if [ -n "$HOST_ROOT" ] && [ "$HOST_ROOT" != "/" ]; then
echo "* Setting up /lib/modules links from host"
ln -s /lib/modules $HOST_ROOT/lib/modules
# If HOST_ROOT is set, but HOST_ROOT/proc does not exist
# link real /proc to HOST_ROOT/proc, so that Falco can run gracefully.
# This is mostly useful when dealing with an hypervisor, like aws Fargate,
# where the container running Falco does not need to bind-mount the host proc volume,
# and its /proc already sees all task processes because it shares the same namespace.
if [ ! -d "$HOST_ROOT/proc" ]; then
echo "* Setting up /proc links from host"
ln -s "/proc" "$HOST_ROOT/proc"
fi
fi
exec "$@"

View File

@@ -169,6 +169,61 @@ syscall_event_drops:
syscall_event_timeouts:
max_consecutives: 1000
# --- [Description]
#
# This is an index that controls the dimension of the syscall buffers.
# The syscall buffer is the shared space between Falco and its drivers where all the syscall events
# are stored.
# Falco uses a syscall buffer for every online CPU, and all these buffers share the same dimension.
# So this parameter allows you to control the size of all the buffers!
#
# --- [Usage]
#
# You can choose between different indexes: from `1` to `10` (`0` is reserved for future uses).
# Every index corresponds to a dimension in bytes:
#
# [(*), 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
#
# As you can see the `0` index is reserved, while the index `1` corresponds to
# `1 MB` and so on.
#
# These dimensions in bytes derive from the fact that the buffer size must be:
# (1) a power of 2.
# (2) a multiple of your system_page_dimension.
# (3) greater than `2 * (system_page_dimension)`.
#
# According to these constraints is possible that sometimes you cannot use all the indexes, let's consider an
# example to better understand it:
# If you have a `page_size` of 1 MB the first available buffer size is 4 MB because 2 MB is exactly
# `2 * (system_page_size)` -> `2 * 1 MB`, but this is not enough we need more than `2 * (system_page_size)`!
# So from this example is clear that if you have a page size of 1 MB the first index that you can use is `3`.
#
# Please note: this is a very extreme case just to let you understand the mechanism, usually the page size is something
# like 4 KB so you have no problem at all and you can use all the indexes (from `1` to `10`).
#
# To check your system page size use the Falco `--page-size` command line option. The output on a system with a page
# size of 4096 Bytes (4 KB) should be the following:
#
# "Your system page size is: 4096 bytes."
#
# --- [Suggestions]
#
# Before the introduction of this param the buffer size was fixed to 8 MB (so index `4`, as you can see
# in the default value below).
# You can increase the buffer size when you face syscall drops. A size of 16 MB (so index `5`) can reduce
# syscall drops in production-heavy systems without noticeable impact. Very large buffers however could
# slow down the entire machine.
# On the other side you can try to reduce the buffer size to speed up the system, but this could
# increase the number of syscall drops!
# As a final remark consider 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 the process virtual memory.
# Please pay attention when you use this parameter and change it only if the default size doesn't fit your use case.
syscall_buf_size_preset: 4
# Falco continuously monitors outputs performance. When an output channel does not allow
# to deliver an alert within a given deadline, an error is reported indicating
# which output is blocking notifications.

View File

@@ -37,6 +37,8 @@ set(
app_actions/print_support.cpp
app_actions/print_syscall_events.cpp
app_actions/print_version.cpp
app_actions/print_page_size.cpp
app_actions/compute_syscall_buffer_size.cpp
app_actions/select_event_sources.cpp
app_actions/start_grpc_server.cpp
app_actions/start_webserver.cpp

View File

@@ -0,0 +1,70 @@
/*
Copyright (C) 2022 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 "application.h"
using namespace falco::app;
/* These indexes could change over the Falco releases. */
#define MIN_INDEX 1
#define MAX_INDEX 10
#define DEFAULT_BYTE_SIZE 1 << 23
application::run_result application::configure_syscall_buffer_size()
{
/* We don't need to compute the syscall buffer dimension if we are in capture mode or if the
* the syscall source is not enabled.
*/
if(is_capture_mode() || m_state->enabled_sources.find(falco_common::syscall_source) == m_state->enabled_sources.end())
{
return run_result::ok();
}
uint16_t index = m_state->config->m_syscall_buf_size_preset;
if(index < MIN_INDEX || index > MAX_INDEX)
{
return run_result::fatal("The index must be between '" + std::to_string(MIN_INDEX) + "' and '" + std::to_string(MAX_INDEX) + "'\n");
}
/* Sizes from `1 MB` to `512 MB`. The index `0` is reserved, users cannot use it! */
std::vector<uint32_t> vect{0, 1 << 20, 1 << 21, 1 << 22, DEFAULT_BYTE_SIZE, 1 << 24, 1 << 25, 1 << 26, 1 << 27, 1 << 28, 1 << 29};
uint64_t chosen_size = vect[index];
/* If the page size is not valid we return here. */
long page_size = getpagesize();
if(page_size <= 0)
{
falco_logger::log(LOG_WARNING, "Unable to get the system page size through 'getpagesize()'. Try to use the default syscall buffer dimension: " + std::to_string(DEFAULT_BYTE_SIZE) + " bytes.\n");
return run_result::ok();
}
/* Check if the chosen size is a multiple of the page size. */
if(chosen_size % page_size != 0)
{
return run_result::fatal("The chosen size '" + std::to_string(chosen_size) + "' is not a multiple of your system page '" + std::to_string(page_size) + "'. Please choose a greater index.\n");
}
/* Check if the chosen size is greater than `2 * page_size`. */
if((chosen_size / page_size) <= 2)
{
return run_result::fatal("The chosen size '" + std::to_string(chosen_size) + "' is not greater than '2 * " + std::to_string(page_size) + "'. Please choose a greater index.\n");
}
m_state->syscall_buffer_bytes_size = chosen_size;
falco_logger::log(LOG_INFO, "The chosen syscall buffer dimension is: " + std::to_string(chosen_size) + " bytes.\n");
return run_result::ok();
}

View File

@@ -91,14 +91,14 @@ application::run_result application::open_live_inspector(
bpf_probe_path = full_path;
}
falco_logger::log(LOG_INFO, "Starting capture with BPF probe. BPF probe path: " + std::string(bpf_probe_path));
inspector->open_bpf(bpf_probe_path, DEFAULT_DRIVER_BUFFER_BYTES_DIM, m_state->ppm_sc_of_interest, m_state->tp_of_interest);
inspector->open_bpf(bpf_probe_path, m_state->syscall_buffer_bytes_size, m_state->ppm_sc_of_interest, m_state->tp_of_interest);
}
else /* Kernel module (default). */
{
try
{
falco_logger::log(LOG_INFO, "Starting capture with Kernel module.");
inspector->open_kmod(DEFAULT_DRIVER_BUFFER_BYTES_DIM, m_state->ppm_sc_of_interest, m_state->tp_of_interest);
inspector->open_kmod(m_state->syscall_buffer_bytes_size, m_state->ppm_sc_of_interest, m_state->tp_of_interest);
}
catch(sinsp_exception &e)
{
@@ -108,7 +108,7 @@ application::run_result application::open_live_inspector(
{
falco_logger::log(LOG_ERR, "Unable to load the driver.\n");
}
inspector->open_kmod(DEFAULT_DRIVER_BUFFER_BYTES_DIM, m_state->ppm_sc_of_interest, m_state->tp_of_interest);
inspector->open_kmod(m_state->syscall_buffer_bytes_size, m_state->ppm_sc_of_interest, m_state->tp_of_interest);
}
}
}

View File

@@ -0,0 +1,37 @@
/*
Copyright (C) 2022 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 "application.h"
using namespace falco::app;
application::run_result application::print_page_size()
{
if(m_options.print_page_size)
{
long page_size = getpagesize();
if(page_size <= 0)
{
return run_result::fatal("\nUnable to get the system page size through 'getpagesize()'\n");
}
else
{
falco_logger::log(LOG_INFO, "Your system page size is: " + std::to_string(page_size) + " bytes.\n");
}
return run_result::exit();
}
return run_result::ok();
}

View File

@@ -335,12 +335,7 @@ application::run_result application::process_events()
try
{
falco_logger::log(LOG_DEBUG, "Opening event source '" + source + "'\n");
res = open_live_inspector(src_info->inspector, source);
if (!res.success)
{
return res;
}
open_live_inspector(src_info->inspector, source);
if (m_state->enabled_sources.size() == 1)
{
// optimization: with only one source we don't spawn additional threads

View File

@@ -203,7 +203,9 @@ void cmdline_options::define()
("u,userspace", "Parse events from userspace. To be used in conjunction with the ptrace(2) based driver (pdig)", cxxopts::value(userspace)->default_value("false"))
("V,validate", "Read the contents of the specified rules(s) file and exit. Can be specified multiple times to validate multiple files.", cxxopts::value(validate_rules_filenames), "<rules_file>")
("v", "Verbose output.", cxxopts::value(verbose)->default_value("false"))
("version", "Print version number.", cxxopts::value(print_version_info)->default_value("false"));
("version", "Print version number.", cxxopts::value(print_version_info)->default_value("false"))
("page-size", "Print the system page size (may help you to choose the right syscall buffer size).", cxxopts::value(print_page_size)->default_value("false"));
m_cmdline_opts.set_width(140);
}

View File

@@ -78,6 +78,7 @@ public:
std::vector<std::string> validate_rules_filenames;
bool verbose;
bool print_version_info;
bool print_page_size;
bool parse(int argc, char **argv, std::string &errstr);

View File

@@ -131,6 +131,7 @@ bool application::run(std::string &errstr, bool &restart)
std::list<std::function<run_result()>> run_steps = {
std::bind(&application::print_help, this),
std::bind(&application::print_version, this),
std::bind(&application::print_page_size, this),
std::bind(&application::print_generated_gvisor_config, this),
std::bind(&application::print_ignored_events, this),
std::bind(&application::print_syscall_events, this),
@@ -151,6 +152,7 @@ bool application::run(std::string &errstr, bool &restart)
std::bind(&application::daemonize, this),
std::bind(&application::init_outputs, this),
std::bind(&application::init_clients, this),
std::bind(&application::configure_syscall_buffer_size, this),
#ifndef MINIMAL_BUILD
std::bind(&application::start_grpc_server, this),
std::bind(&application::start_webserver, this),

View File

@@ -116,6 +116,9 @@ private:
// Set of tracepoints we want the driver to capture
std::unordered_set<uint32_t> tp_of_interest;
// Dimension of the syscall buffer in bytes.
uint64_t syscall_buffer_bytes_size;
#ifndef MINIMAL_BUILD
falco::grpc::server grpc_server;
std::thread grpc_server_thread;
@@ -247,9 +250,11 @@ private:
run_result print_support();
run_result print_syscall_events();
run_result print_version();
run_result print_page_size();
run_result process_events();
run_result select_event_sources();
void configure_interesting_sets();
application::run_result configure_syscall_buffer_size();
#ifndef MINIMAL_BUILD
run_result start_grpc_server();
run_result start_webserver();
@@ -289,6 +294,7 @@ private:
std::string source, // an empty source represents capture mode
run_result* res) noexcept;
/* Returns true if we are in capture mode. */
inline bool is_capture_mode() const
{
return !m_options.trace_filename.empty();

View File

@@ -285,6 +285,11 @@ void falco_configuration::init(string conf_filename, const vector<string> &cmdli
throw logic_error("Error reading config file(" + m_config_file + "): metadata download watch frequency seconds must be an unsigned integer > 0");
}
/* We put this value in the configuration file because in this way we can change the dimension at every reload.
* The default value is `4` -> 8 MB.
*/
m_syscall_buf_size_preset = m_config->get_scalar<uint64_t>("syscall_buf_size_preset", 4);
std::set<std::string> load_plugins;
bool load_plugins_node_defined = m_config->is_defined("load_plugins");

View File

@@ -269,6 +269,9 @@ public:
uint32_t m_metadata_download_chunk_wait_us;
uint32_t m_metadata_download_watch_freq_sec;
// Index corresponding to the syscall buffer dimension.
uint64_t m_syscall_buf_size_preset;
std::vector<plugin_config> m_plugins;
private: