From 90b888f4f3ae54512e7815fc53bf2c8727a45c25 Mon Sep 17 00:00:00 2001 From: Grzegorz Nosek Date: Mon, 22 Jul 2024 08:15:57 +0200 Subject: [PATCH 1/2] new(scap): introduce linux hostinfo platform This is a minimal Linux platformm intended to be useful with source plugins that do not handle syscall data but still want access to some info about the machine they're running on. Currently collected data includes: - machine info - agent info - interface list Signed-off-by: Grzegorz Nosek --- userspace/libscap/linux/CMakeLists.txt | 11 ++- .../linux/scap_linux_hostinfo_platform.c | 73 +++++++++++++++++++ userspace/libscap/linux/scap_linux_platform.h | 16 ++++ userspace/libscap/scap.c | 8 +- 4 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 userspace/libscap/linux/scap_linux_hostinfo_platform.c diff --git a/userspace/libscap/linux/CMakeLists.txt b/userspace/libscap/linux/CMakeLists.txt index 471721f4e2..4d51534ca0 100644 --- a/userspace/libscap/linux/CMakeLists.txt +++ b/userspace/libscap/linux/CMakeLists.txt @@ -14,7 +14,16 @@ # See the License for the specific language governing permissions and # limitations under the License. # -add_library(scap_platform STATIC scap_linux_platform.c scap_procs.c scap_fds.c scap_userlist.c scap_iflist.c scap_cgroup.c scap_machine_info.c) +add_library(scap_platform + STATIC + scap_linux_platform.c + scap_linux_hostinfo_platform.c + scap_procs.c + scap_fds.c + scap_userlist.c + scap_iflist.c + scap_cgroup.c + scap_machine_info.c) target_include_directories(scap_platform PUBLIC $) target_link_libraries(scap_platform PRIVATE scap_error scap_platform_util) add_dependencies(scap_platform uthash) diff --git a/userspace/libscap/linux/scap_linux_hostinfo_platform.c b/userspace/libscap/linux/scap_linux_hostinfo_platform.c new file mode 100644 index 0000000000..258d591919 --- /dev/null +++ b/userspace/libscap/linux/scap_linux_hostinfo_platform.c @@ -0,0 +1,73 @@ +/* +Copyright (C) 2024 The Falco Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*/ + +#include + +#include +#include +#include +#include + +#include +#include + +static void scap_linux_hostinfo_free_platform(struct scap_platform* platform) +{ + free(platform); +} + +int32_t scap_linux_hostinfo_init_platform(struct scap_platform* platform, char* lasterr, struct scap_engine_handle engine, struct scap_open_args* oargs) +{ + int rc; + + if(scap_os_get_machine_info(&platform->m_machine_info, lasterr) != SCAP_SUCCESS) + { + return SCAP_FAILURE; + } + + scap_os_get_agent_info(&platform->m_agent_info); + + rc = scap_linux_create_iflist(platform); + if(rc != SCAP_SUCCESS) + { + scap_linux_hostinfo_free_platform(platform); + return rc; + } + + return SCAP_SUCCESS; +} + +static const struct scap_platform_vtable scap_linux_hostinfo_platform_vtable = { + .init_platform = scap_linux_hostinfo_init_platform, + .refresh_addr_list = scap_linux_create_iflist, + .free_platform = scap_linux_hostinfo_free_platform, +}; + +struct scap_platform* scap_linux_hostinfo_alloc_platform() +{ + struct scap_linux_platform* platform = calloc(1, sizeof(*platform)); + + if(platform == NULL) + { + return NULL; + } + + struct scap_platform* generic = &platform->m_generic; + generic->m_vtable = &scap_linux_hostinfo_platform_vtable; + + return generic; +} diff --git a/userspace/libscap/linux/scap_linux_platform.h b/userspace/libscap/linux/scap_linux_platform.h index 55de6a66d0..c08327873e 100644 --- a/userspace/libscap/linux/scap_linux_platform.h +++ b/userspace/libscap/linux/scap_linux_platform.h @@ -103,6 +103,22 @@ struct scap_linux_platform struct scap_platform* scap_linux_alloc_platform(proc_entry_callback proc_callback, void* proc_callback_context); +/** + * @brief A lightweight Linux platform that only collects static host information + * + * This is useful with source plugins that do not handle syscall data but still want access + * to some info about the machine they're running on. Currently collected data includes: + * - machine info + * - agent info + * - interface list + */ +struct scap_linux_hostinfo_platform +{ + struct scap_platform m_generic; +}; + +struct scap_platform* scap_linux_hostinfo_alloc_platform(); + #ifdef __cplusplus }; #endif diff --git a/userspace/libscap/scap.c b/userspace/libscap/scap.c index 04a83aeaca..00a046df72 100644 --- a/userspace/libscap/scap.c +++ b/userspace/libscap/scap.c @@ -35,12 +35,16 @@ limitations under the License. // The test_input and source_plugin engines can optionally use a linux_platform // but only on an actual Linux system. // -// Still, to compile properly on non-Linux, provide an implementation -// of scap_linux_alloc_platform() that always fails at runtime. +// Still, to compile properly on non-Linux, provide implementations +// of scap_linux_alloc_platform() and scap_linux_hostinfo_alloc_platform() that always fail at runtime. struct scap_platform* scap_linux_alloc_platform(proc_entry_callback proc_callback, void* proc_callback_context) { return NULL; } +struct scap_platform* scap_linux_hostinfo_alloc_platform() +{ + return NULL; +} #endif const char* scap_getlasterr(scap_t* handle) From 2118fcd9f9d3d79a640fcd17e1c3585574de7cab Mon Sep 17 00:00:00 2001 From: Grzegorz Nosek Date: Mon, 22 Jul 2024 08:16:11 +0200 Subject: [PATCH 2/2] new(sinsp)!: support linux_hostinfo_platform in sinsp::open_plugin Rather than passing the mode directly, introduce a new enum that describes both the mode and the platform to use. Fixes: #2281 Signed-off-by: Grzegorz Nosek --- userspace/libsinsp/sinsp.cpp | 28 +++++++++++++++++--------- userspace/libsinsp/sinsp.h | 12 ++++++++++- userspace/libsinsp/test/plugins.ut.cpp | 13 ++++++++++-- 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/userspace/libsinsp/sinsp.cpp b/userspace/libsinsp/sinsp.cpp index 86b722df41..f1d6458c00 100644 --- a/userspace/libsinsp/sinsp.cpp +++ b/userspace/libsinsp/sinsp.cpp @@ -553,7 +553,8 @@ void sinsp::open_savefile(const std::string& filename, int fd) #endif } -void sinsp::open_plugin(const std::string& plugin_name, const std::string& plugin_open_params, sinsp_mode_t mode) +void sinsp::open_plugin(const std::string& plugin_name, const std::string& plugin_open_params, + sinsp_plugin_platform platform_type) { #ifdef HAS_ENGINE_SOURCE_PLUGIN scap_open_args oargs {}; @@ -564,16 +565,23 @@ void sinsp::open_plugin(const std::string& plugin_name, const std::string& plugi oargs.engine_params = ¶ms; scap_platform* platform; - switch(mode) + sinsp_mode_t mode; + switch(platform_type) { - case SINSP_MODE_PLUGIN: - platform = scap_generic_alloc_platform(::on_new_entry_from_proc, this); - break; - case SINSP_MODE_LIVE: - platform = scap_linux_alloc_platform(::on_new_entry_from_proc, this); - break; - default: - throw sinsp_exception("Unsupported mode for SOURCE_PLUGIN engine"); + case sinsp_plugin_platform::SINSP_PLATFORM_GENERIC: + mode = SINSP_MODE_PLUGIN; + platform = scap_generic_alloc_platform(::on_new_entry_from_proc, this); + break; + case sinsp_plugin_platform::SINSP_PLATFORM_HOSTINFO: + mode = SINSP_MODE_PLUGIN; + platform = scap_linux_hostinfo_alloc_platform(); + break; + case sinsp_plugin_platform::SINSP_PLATFORM_FULL: + mode = SINSP_MODE_LIVE; + platform = scap_linux_alloc_platform(::on_new_entry_from_proc, this); + break; + default: + throw sinsp_exception("Unsupported mode for SOURCE_PLUGIN engine"); } open_common(&oargs, &scap_source_plugin_engine, platform, mode); #else diff --git a/userspace/libsinsp/sinsp.h b/userspace/libsinsp/sinsp.h index a709cc44a2..8e6d89a230 100644 --- a/userspace/libsinsp/sinsp.h +++ b/userspace/libsinsp/sinsp.h @@ -139,6 +139,16 @@ enum sinsp_mode_t SINSP_MODE_TEST, }; +/** + * @brief Possible platforms to use with plugins + */ +enum class sinsp_plugin_platform +{ + SINSP_PLATFORM_GENERIC, //!< generic platform, no system information collected + SINSP_PLATFORM_HOSTINFO, //!< basic host information collected, for non-syscall source plugins + SINSP_PLATFORM_FULL, //!< full system information collected, for syscall source plugins +}; + /** @defgroup inspector Main library @{ */ @@ -168,7 +178,7 @@ class SINSP_PUBLIC sinsp : public capture_stats_source virtual void open_nodriver(bool full_proc_scan = false); virtual void open_savefile(const std::string &filename, int fd = 0); virtual void open_plugin(const std::string& plugin_name, const std::string& plugin_open_params, - sinsp_mode_t mode = SINSP_MODE_PLUGIN); + sinsp_plugin_platform platform_type); virtual void open_gvisor(const std::string &config_path, const std::string &root_path, bool no_events = false, int epoll_timeout = -1); /*[EXPERIMENTAL] This API could change between releases, we are trying to find the right configuration to deploy the modern bpf probe: * `cpus_for_each_buffer` and `online_only` are the 2 experimental params. The first one allows associating more than one CPU to a single ring buffer. diff --git a/userspace/libsinsp/test/plugins.ut.cpp b/userspace/libsinsp/test/plugins.ut.cpp index 1821ddc35d..7f5535ebfb 100644 --- a/userspace/libsinsp/test/plugins.ut.cpp +++ b/userspace/libsinsp/test/plugins.ut.cpp @@ -273,7 +273,13 @@ TEST_F(sinsp_with_test_input, plugin_syscall_source) // we will not use the test scap engine here, but open the src plugin instead // note: we configure the plugin to just emit 1 event through its open params - m_inspector.open_plugin(src_pl->name(), "1"); + m_inspector.open_plugin(src_pl->name(), "1", sinsp_plugin_platform::SINSP_PLATFORM_HOSTINFO); + +#ifdef __linux__ + // The LINUX_HOSTINFO platform type fills in machine_info, but only on Linux + // (non-Linux platforms have a stub implementation in scap.c) + ASSERT_GT(m_inspector.get_machine_info()->num_cpus, 0); +#endif auto evt = next_event(); ASSERT_NE(evt, nullptr); @@ -310,7 +316,10 @@ TEST_F(sinsp_with_test_input, plugin_custom_source) // we will not use the test scap engine here, but open the src plugin instead // note: we configure the plugin to just emit 1 event through its open params - m_inspector.open_plugin(src_pl->name(), "1"); + m_inspector.open_plugin(src_pl->name(), "1", sinsp_plugin_platform::SINSP_PLATFORM_GENERIC); + + // the GENERIC platform type does not fill in machine_info + ASSERT_EQ(m_inspector.get_machine_info()->num_cpus, 0); auto evt = next_event(); ASSERT_NE(evt, nullptr);