Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
330 changes: 330 additions & 0 deletions .claude/commands/update-falco-libs.md

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,6 @@
path = builder/third_party/bpftool
url = https://github.com/libbpf/bpftool
branch = v7.3.0
[submodule "builder/third_party/falcosecurity-plugins"]
path = builder/third_party/falcosecurity-plugins
url = https://github.com/falcosecurity/plugins.git
16 changes: 16 additions & 0 deletions builder/install/00-golang.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env bash
set -e

GO_VERSION=1.23.7
ARCH=$(uname -m)
case ${ARCH} in
x86_64) GO_ARCH=amd64 ;;
aarch64) GO_ARCH=arm64 ;;
ppc64le) GO_ARCH=ppc64le ;;
s390x) GO_ARCH=s390x ;;
esac

curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-${GO_ARCH}.tar.gz" | tar -C /usr/local -xz
export PATH="/usr/local/go/bin:${PATH}"
echo "export PATH=/usr/local/go/bin:${PATH}" >> /etc/profile.d/golang.sh
go version
20 changes: 20 additions & 0 deletions builder/install/01-container-plugin.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -e

export PATH="/usr/local/go/bin:${PATH}"

cd third_party/falcosecurity-plugins/plugins/container

cp ../../LICENSE "${LICENSE_DIR}/falcosecurity-plugins-container-${CONTAINER_PLUGIN_VERSION}" 2> /dev/null || true

# Remove static libstdc++ linking — not needed since we control the runtime
# image, and libstdc++-static is not available in CentOS Stream 10.
sed -i '/-static-libgcc\|-static-libstdc++/d' CMakeLists.txt

cmake -B build -S . \
-DCMAKE_BUILD_TYPE=Release \
-DENABLE_ASYNC=ON \
-DENABLE_TESTS=OFF
cmake --build build --target container --parallel "${NPROCS}"

install -m 755 build/libcontainer.so /usr/local/lib64/libcontainer.so
1 change: 1 addition & 0 deletions builder/install/versions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ export GPERFTOOLS_VERSION=2.16
export UTHASH_VERSION=v1.9.8
export YAMLCPP_VERSION=0.8.0
export LIBBPF_VERSION=v1.3.4
export CONTAINER_PLUGIN_VERSION=0.6.3
1 change: 1 addition & 0 deletions builder/third_party/falcosecurity-plugins
Submodule falcosecurity-plugins added at fb2ad6
1 change: 0 additions & 1 deletion collector/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ set(USE_BUNDLED_DEPS OFF CACHE BOOL "Enable bundled dependencies instead of usin
set(USE_BUNDLED_CARES OFF CACHE BOOL "Enable bundled dependencies instead of using the system ones" FORCE)
set(BUILD_LIBSCAP_GVISOR OFF CACHE BOOL "Do not build gVisor support" FORCE)
set(MINIMAL_BUILD OFF CACHE BOOL "Minimal" FORCE)
set(SINSP_SLIM_THREADINFO ON CACHE BOOL "Slim threadinfo" FORCE)
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build position independent libraries and executables" FORCE)
set(LIBELF_LIB_SUFFIX ".so" CACHE STRING "Use libelf.so" FORCE)

Expand Down
1 change: 1 addition & 0 deletions collector/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ container/bin/collector: cmake-build/collector
mkdir -p container/bin
cp "$(COLLECTOR_BIN_DIR)/collector" container/bin/collector
cp "$(COLLECTOR_BIN_DIR)/self-checks" container/bin/self-checks
docker cp $(COLLECTOR_BUILDER_NAME):/usr/local/lib64/libcontainer.so container/bin/libcontainer.so

.PHONY: collector
collector: container/bin/collector txt-files
Expand Down
1 change: 1 addition & 0 deletions collector/container/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ COPY container/THIRD_PARTY_NOTICES/ /THIRD_PARTY_NOTICES/
COPY kernel-modules /kernel-modules
COPY container/bin/collector /usr/local/bin/
COPY container/bin/self-checks /usr/local/bin/self-checks
COPY container/bin/libcontainer.so /usr/local/lib64/libcontainer.so
COPY container/status-check.sh /usr/local/bin/status-check.sh

EXPOSE 8080 9090
Expand Down
25 changes: 0 additions & 25 deletions collector/lib/ContainerEngine.h

This file was deleted.

21 changes: 8 additions & 13 deletions collector/lib/ContainerMetadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <libsinsp/sinsp.h>

#include "Logging.h"
#include "system-inspector/EventExtractor.h"

namespace collector {
Expand All @@ -20,19 +21,13 @@ std::string ContainerMetadata::GetNamespace(const std::string& container_id) {
}

std::string ContainerMetadata::GetContainerLabel(const std::string& container_id, const std::string& label) {
auto containers = inspector_->m_container_manager.get_containers();
const auto& container = containers->find(container_id);
if (container == containers->end()) {
return "";
}

const auto& labels = container->second->m_labels;
const auto& label_it = labels.find(label);
if (label_it == labels.end()) {
return "";
}

return label_it->second;
// Container labels are no longer available through the sinsp API.
// The container plugin provides container metadata via filter fields
// (e.g., container.label) but not through a programmatic lookup API.
CLOG_THROTTLED(DEBUG, std::chrono::seconds(300))
<< "Container label lookup by container ID is not supported: "
<< "container_id=" << container_id << " label=" << label;
return "";
}

} // namespace collector
4 changes: 2 additions & 2 deletions collector/lib/NetworkSignalHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,11 @@ std::optional<Connection> NetworkSignalHandler::GetConnection(sinsp_evt* evt) {
const Endpoint* local = is_server ? &server : &client;
const Endpoint* remote = is_server ? &client : &server;

const std::string* container_id = event_extractor_->get_container_id(evt);
const char* container_id = event_extractor_->get_container_id(evt);
if (!container_id) {
return std::nullopt;
}
return {Connection(*container_id, *local, *remote, l4proto, is_server)};
return {Connection(container_id, *local, *remote, l4proto, is_server)};
}

SignalHandler::Result NetworkSignalHandler::HandleSignal(sinsp_evt* evt) {
Expand Down
7 changes: 6 additions & 1 deletion collector/lib/Process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <libsinsp/sinsp.h>

#include "CollectorStats.h"
#include "Utility.h"
#include "system-inspector/Service.h"

namespace collector {
Expand Down Expand Up @@ -32,7 +33,11 @@ std::string Process::container_id() const {
WaitForProcessInfo();

if (system_inspector_threadinfo_) {
return system_inspector_threadinfo_->m_container_id;
for (const auto& [subsys, cgroup_path] : system_inspector_threadinfo_->cgroups()) {
if (auto id = ExtractContainerIDFromCgroup(cgroup_path)) {
return std::string(*id);
}
}
}

return NOT_AVAILABLE;
Expand Down
30 changes: 17 additions & 13 deletions collector/lib/ProcessSignalFormatter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

#include <uuid/uuid.h>

#include <libsinsp/sinsp.h>
#include <libsinsp/thread_manager.h>

#include <google/protobuf/util/time_util.h>

#include "internalapi/sensor/signal_iservice.pb.h"
Expand Down Expand Up @@ -59,6 +62,7 @@ std::string extract_proc_args(sinsp_threadinfo* tinfo) {
ProcessSignalFormatter::ProcessSignalFormatter(
sinsp* inspector,
const CollectorConfig& config) : event_names_(EventNames::GetInstance()),
inspector_(inspector),
event_extractor_(std::make_unique<system_inspector::EventExtractor>()),
container_metadata_(inspector),
config_(config) {
Expand Down Expand Up @@ -176,8 +180,8 @@ ProcessSignal* ProcessSignalFormatter::CreateProcessSignal(sinsp_evt* event) {
signal->set_allocated_time(timestamp);

// set container_id
if (const std::string* container_id = event_extractor_->get_container_id(event)) {
signal->set_container_id(*container_id);
if (const char* container_id = event_extractor_->get_container_id(event)) {
signal->set_container_id(container_id);
}

// set process lineage
Expand Down Expand Up @@ -232,16 +236,16 @@ ProcessSignal* ProcessSignalFormatter::CreateProcessSignal(sinsp_threadinfo* tin
signal->set_pid(tinfo->m_pid);

// set user and group id credentials
signal->set_uid(tinfo->m_user.uid());
signal->set_gid(tinfo->m_group.gid());
signal->set_uid(tinfo->m_uid);
signal->set_gid(tinfo->m_gid);

// set time
auto timestamp = Allocate<Timestamp>();
*timestamp = TimeUtil::NanosecondsToTimestamp(tinfo->m_clone_ts);
signal->set_allocated_time(timestamp);

// set container_id
signal->set_container_id(tinfo->m_container_id);
signal->set_container_id(GetContainerID(*tinfo, *inspector_->m_thread_manager));

// set process lineage
std::vector<LineageInfo> lineage;
Expand All @@ -265,11 +269,11 @@ std::string ProcessSignalFormatter::ProcessDetails(sinsp_evt* event) {
std::stringstream ss;
const std::string* path = event_extractor_->get_exepath(event);
const std::string* name = event_extractor_->get_comm(event);
const std::string* container_id = event_extractor_->get_container_id(event);
const char* container_id = event_extractor_->get_container_id(event);
const char* args = event_extractor_->get_proc_args(event);
const int64_t* pid = event_extractor_->get_pid(event);

ss << "Container: " << (container_id ? *container_id : "null")
ss << "Container: " << (container_id ? container_id : "null")
<< ", Name: " << (name ? *name : "null")
<< ", PID: " << (pid ? *pid : -1)
<< ", Path: " << (path ? *path : "null")
Expand Down Expand Up @@ -327,7 +331,7 @@ void ProcessSignalFormatter::GetProcessLineage(sinsp_threadinfo* tinfo,
return;
}
}
sinsp_threadinfo::visitor_func_t visitor = [this, &lineage](sinsp_threadinfo* pt) {
sinsp_thread_manager::visitor_func_t visitor = [this, &lineage](sinsp_threadinfo* pt) {
if (pt == NULL) {
return false;
}
Expand All @@ -341,13 +345,13 @@ void ProcessSignalFormatter::GetProcessLineage(sinsp_threadinfo* tinfo,
//
// In back-ported eBPF probes, `m_vpid` will not be set for containers
// running when collector comes online because /proc/{pid}/status does
// not contain namespace information, so `m_container_id` is checked
// instead. `m_container_id` is not enough on its own to identify
// not contain namespace information, so the container ID is checked
// instead. The container ID is not enough on its own to identify
// containerized processes, because it is not guaranteed to be set on
// all platforms.
//
if (pt->m_vpid == 0) {
if (pt->m_container_id.empty()) {
if (GetContainerID(*pt, *inspector_->m_thread_manager).empty()) {
return false;
}
} else if (pt->m_pid == pt->m_vpid) {
Expand All @@ -361,7 +365,7 @@ void ProcessSignalFormatter::GetProcessLineage(sinsp_threadinfo* tinfo,
// Collapse parent child processes that have the same path
if (lineage.empty() || (lineage.back().parent_exec_file_path() != pt->m_exepath)) {
LineageInfo info;
info.set_parent_uid(pt->m_user.uid());
info.set_parent_uid(pt->m_uid);
info.set_parent_exec_file_path(pt->m_exepath);
lineage.push_back(info);
}
Expand All @@ -373,7 +377,7 @@ void ProcessSignalFormatter::GetProcessLineage(sinsp_threadinfo* tinfo,

return true;
};
mt->traverse_parent_state(visitor);
inspector_->m_thread_manager->traverse_parent_state(*mt, visitor);
CountLineage(lineage);
}

Expand Down
1 change: 1 addition & 0 deletions collector/lib/ProcessSignalFormatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class ProcessSignalFormatter : public ProtoSignalFormatter<sensor::SignalStreamM
void CountLineage(const std::vector<LineageInfo>& lineage);

const EventNames& event_names_;
sinsp* inspector_;
std::unique_ptr<system_inspector::EventExtractor> event_extractor_;
ContainerMetadata container_metadata_;

Expand Down
13 changes: 12 additions & 1 deletion collector/lib/Utility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ extern "C" {
#include <utf8_validity.h>

#include <libsinsp/sinsp.h>
#include <libsinsp/thread_manager.h>

#include <google/protobuf/util/json_util.h>

Expand Down Expand Up @@ -57,9 +58,19 @@ const char* SignalName(int signum) {
}
}

std::string GetContainerID(sinsp_threadinfo& tinfo, sinsp_thread_manager& thread_manager) {
const auto* accessor = thread_manager.get_field_accessor("container_id");
if (!accessor) {
return {};
}
std::string container_id;
tinfo.get_dynamic_field(*accessor, container_id);
return container_id;
}

std::ostream& operator<<(std::ostream& os, const sinsp_threadinfo* t) {
if (t) {
os << "Container: \"" << t->m_container_id << "\", Name: " << t->m_comm << ", PID: " << t->m_pid << ", Args: " << t->m_exe;
os << "Name: " << t->m_comm << ", PID: " << t->m_pid << ", Args: " << t->m_exe;
} else {
os << "NULL\n";
}
Expand Down
5 changes: 5 additions & 0 deletions collector/lib/Utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

// forward declarations
class sinsp_threadinfo;
class sinsp_thread_manager;

namespace collector {

Expand Down Expand Up @@ -65,6 +66,10 @@ std::string Str(Args&&... args) {

std::ostream& operator<<(std::ostream& os, const sinsp_threadinfo* t);

// Extract container ID from a threadinfo using the dynamic field written by
// the container plugin. Returns an empty string if unavailable.
std::string GetContainerID(sinsp_threadinfo& tinfo, sinsp_thread_manager& thread_manager);

// UUIDStr returns UUID in string format.
const char* UUIDStr();

Expand Down
4 changes: 4 additions & 0 deletions collector/lib/system-inspector/EventExtractor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ namespace collector::system_inspector {
void EventExtractor::Init(sinsp* inspector) {
for (auto* wrapper : wrappers_) {
std::unique_ptr<sinsp_filter_check> check = FilterList().new_filter_check_from_fldname(wrapper->event_name, inspector, true);
if (!check) {
CLOG(WARNING) << "Filter check not available for field: " << wrapper->event_name;
continue;
}
check->parse_field_name(wrapper->event_name, true, false);
wrapper->filter_check.reset(check.release());
}
Expand Down
Loading
Loading