diff --git a/driver/capture_macro.h b/driver/capture_macro.h index f78e178a1e..0faafb84f8 100644 --- a/driver/capture_macro.h +++ b/driver/capture_macro.h @@ -31,4 +31,4 @@ or GPL2.txt for full copies of the license. #define BPF_HTTP_PREFIX 0x50545448 /* Convert seconds to nanoseconds */ -#define SECOND_TO_NS 1000000000 +#define SECOND_TO_NS 1000000000ULL diff --git a/userspace/libscap/CMakeLists.txt b/userspace/libscap/CMakeLists.txt index a441b5bea2..5822454a08 100644 --- a/userspace/libscap/CMakeLists.txt +++ b/userspace/libscap/CMakeLists.txt @@ -66,6 +66,15 @@ list(APPEND targetfiles scap_userlist.c scap_suppress.c) +if(CMAKE_SYSTEM_NAME MATCHES "Linux") + list(APPEND targetfiles linux/scap_machine_info.c) +elseif(WIN32) + list(APPEND targetfiles win32/scap_machine_info.c) +elseif(APPLE) + list(APPEND targetfiles macos/scap_machine_info.c) +endif() + + if(CMAKE_SYSTEM_NAME MATCHES "Linux") include_directories(${CMAKE_CURRENT_SOURCE_DIR}) # temporary include_directories(${PROJECT_BINARY_DIR}/driver/src) diff --git a/userspace/libscap/linux/scap_linux_platform.c b/userspace/libscap/linux/scap_linux_platform.c index ce891928f9..3504a97e74 100644 --- a/userspace/libscap/linux/scap_linux_platform.c +++ b/userspace/libscap/linux/scap_linux_platform.c @@ -31,8 +31,6 @@ limitations under the License. #include #include -#define SECOND_TO_NS 1000000000 - static int32_t scap_linux_close_platform(struct scap_platform* platform) { struct scap_linux_platform* linux_platform = (struct scap_linux_platform*)platform; @@ -54,151 +52,12 @@ static void scap_linux_free_platform(struct scap_platform* platform) free(platform); } -static void scap_linux_retrieve_agent_info(scap_agent_info* agent_info) -{ - agent_info->start_ts_epoch = 0; - agent_info->start_time = 0; - - /* Info 1: - * - * Get epoch timestamp based on procfs stat, only used for (constant) agent start time reporting. - */ - struct stat st = {0}; - if(stat("/proc/self/cmdline", &st) == 0) - { - agent_info->start_ts_epoch = st.st_ctim.tv_sec * (uint64_t) SECOND_TO_NS + st.st_ctim.tv_nsec; - } - - /* Info 2: - * - * Get /proc/self/stat start_time (22nd item) to calculate subsequent snapshots of the elapsed time - * of the agent for CPU usage calculations, e.g. sysinfo uptime - /proc/self/stat start_time. - */ - FILE* f; - if((f = fopen("/proc/self/stat", "r"))) - { - unsigned long long stat_start_time = 0; // unit: USER_HZ / jiffies / clock ticks - long hz = 100; -#ifdef _SC_CLK_TCK - if ((hz = sysconf(_SC_CLK_TCK)) < 0) - { - hz = 100; - ASSERT(false); - } -#endif - if(fscanf(f, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %*u %*u %*u %*u %*d %*d %*d %*u %llu", &stat_start_time)) - { - agent_info->start_time = (double)stat_start_time / hz; // unit: seconds as type (double) - } - fclose(f); - } - - /* Info 3: - * - * Kernel release `uname -r` of the machine the agent is running on. - */ - - struct utsname uts; - uname(&uts); - snprintf(agent_info->uname_r, sizeof(agent_info->uname_r), "%s", uts.release); -} - -static uint64_t scap_linux_get_host_boot_time_ns(char* last_err) -{ - uint64_t btime = 0; - char proc_stat[PPM_MAX_PATH_SIZE]; - char line[512]; - - /* Get boot time from btime value in /proc/stat - * ref: https://github.com/falcosecurity/libs/issues/932 - * /proc/uptime and btime in /proc/stat are fed by the same kernel sources. - * - * Multiple ways to get boot time: - * btime in /proc/stat - * calculation via clock_gettime(CLOCK_REALTIME - CLOCK_BOOTTIME) - * calculation via time(NULL) - sysinfo().uptime - * - * Maintainers preferred btime in /proc/stat because: - * value does not depend on calculation using current timestamp - * btime is "static" and doesn't change once set - * btime is available in kernels from 2008 - * CLOCK_BOOTTIME is available in kernels from 2011 (2.6.38 - * - * By scraping btime from /proc/stat, - * it is both the heaviest and most likely to succeed - */ - snprintf(proc_stat, sizeof(proc_stat), "%s/proc/stat", scap_get_host_root()); - FILE* f = fopen(proc_stat, "r"); - if (f == NULL) - { - ASSERT(false); - return 0; - } - - while(fgets(line, sizeof(line), f) != NULL) - { - if(sscanf(line, "btime %" PRIu64, &btime) == 1) - { - fclose(f); - return btime * (uint64_t) SECOND_TO_NS; - } - } - fclose(f); - ASSERT(false); - return 0; -} - -static void scap_get_bpf_stats_enabled(scap_machine_info* machine_info) -{ - machine_info->flags &= ~PPM_BPF_STATS_ENABLED; - FILE* f; - if((f = fopen("/proc/sys/kernel/bpf_stats_enabled", "r"))) - { - uint32_t bpf_stats_enabled = 0; - if(fscanf(f, "%u", &bpf_stats_enabled) == 1) - { - if (bpf_stats_enabled != 0) - { - machine_info->flags |= PPM_BPF_STATS_ENABLED; - } - } - fclose(f); - } -} - -static void scap_gethostname(char* buf, size_t size) -{ - char *env_hostname = getenv(SCAP_HOSTNAME_ENV_VAR); - if(env_hostname != NULL) - { - snprintf(buf, size, "%s", env_hostname); - } - else - { - gethostname(buf, size); - } -} - int32_t scap_linux_init_platform(struct scap_platform* platform, char* lasterr, struct scap_engine_handle engine, struct scap_open_args* oargs) { int rc; struct scap_linux_platform* linux_platform = (struct scap_linux_platform*)platform; linux_platform->m_lasterr = lasterr; - linux_platform->m_engine = engine; - - platform->m_machine_info.num_cpus = sysconf(_SC_NPROCESSORS_ONLN); - platform->m_machine_info.memory_size_bytes = (uint64_t)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE); - scap_gethostname(platform->m_machine_info.hostname, sizeof(platform->m_machine_info.hostname)); - platform->m_machine_info.boot_ts_epoch = scap_linux_get_host_boot_time_ns(lasterr); - if(platform->m_machine_info.boot_ts_epoch == 0) - { - return SCAP_FAILURE; - } - scap_get_bpf_stats_enabled(&platform->m_machine_info); - platform->m_machine_info.reserved3 = 0; - platform->m_machine_info.reserved4 = 0; - linux_platform->m_proc_scan_timeout_ms = oargs->proc_scan_timeout_ms; linux_platform->m_proc_scan_log_interval_ms = oargs->proc_scan_log_interval_ms; linux_platform->m_debug_log_fn = oargs->debug_log_fn; @@ -230,8 +89,6 @@ int32_t scap_linux_init_platform(struct scap_platform* platform, char* lasterr, return rc; } - scap_linux_retrieve_agent_info(&platform->m_agent_info); - return SCAP_SUCCESS; } diff --git a/userspace/libscap/linux/scap_machine_info.c b/userspace/libscap/linux/scap_machine_info.c new file mode 100644 index 0000000000..ea5d004ca8 --- /dev/null +++ b/userspace/libscap/linux/scap_machine_info.c @@ -0,0 +1,171 @@ +/* +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 "scap_machine_info.h" +#include "scap_os_machine_info.h" +#include "scap_limits.h" +#include "scap_assert.h" +#include "scap.h" + +#include +#include +#include +#include +#include + +#define SECOND_TO_NS 1000000000 + +void scap_os_get_agent_info(scap_agent_info* agent_info) +{ + agent_info->start_ts_epoch = 0; + agent_info->start_time = 0; + + /* Info 1: + * + * Get epoch timestamp based on procfs stat, only used for (constant) agent start time reporting. + */ + struct stat st = {0}; + if(stat("/proc/self/cmdline", &st) == 0) + { + agent_info->start_ts_epoch = st.st_ctim.tv_sec * SECOND_TO_NS + st.st_ctim.tv_nsec; + } + + /* Info 2: + * + * Get /proc/self/stat start_time (22nd item) to calculate subsequent snapshots of the elapsed time + * of the agent for CPU usage calculations, e.g. sysinfo uptime - /proc/self/stat start_time. + */ + FILE* f; + if((f = fopen("/proc/self/stat", "r"))) + { + unsigned long long stat_start_time = 0; // unit: USER_HZ / jiffies / clock ticks + long hz = 100; +#ifdef _SC_CLK_TCK + if ((hz = sysconf(_SC_CLK_TCK)) < 0) + { + hz = 100; + ASSERT(false); + } +#endif + if(fscanf(f, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %*u %*u %*u %*u %*d %*d %*d %*u %llu", &stat_start_time)) + { + agent_info->start_time = (double)stat_start_time / hz; // unit: seconds as type (double) + } + fclose(f); + } + + /* Info 3: + * + * Kernel release `uname -r` of the machine the agent is running on. + */ + + struct utsname uts; + uname(&uts); + snprintf(agent_info->uname_r, sizeof(agent_info->uname_r), "%s", uts.release); +} + +static uint64_t scap_linux_get_host_boot_time_ns(char* last_err) +{ + uint64_t btime = 0; + char proc_stat[SCAP_MAX_PATH_SIZE]; + char line[512]; + + /* Get boot time from btime value in /proc/stat + * ref: https://github.com/falcosecurity/libs/issues/932 + * /proc/uptime and btime in /proc/stat are fed by the same kernel sources. + * + * Multiple ways to get boot time: + * btime in /proc/stat + * calculation via clock_gettime(CLOCK_REALTIME - CLOCK_BOOTTIME) + * calculation via time(NULL) - sysinfo().uptime + * + * Maintainers preferred btime in /proc/stat because: + * value does not depend on calculation using current timestamp + * btime is "static" and doesn't change once set + * btime is available in kernels from 2008 + * CLOCK_BOOTTIME is available in kernels from 2011 (2.6.38 + * + * By scraping btime from /proc/stat, + * it is both the heaviest and most likely to succeed + */ + snprintf(proc_stat, sizeof(proc_stat), "%s/proc/stat", scap_get_host_root()); + FILE* f = fopen(proc_stat, "r"); + if (f == NULL) + { + ASSERT(false); + return 0; + } + + while(fgets(line, sizeof(line), f) != NULL) + { + if(sscanf(line, "btime %" PRIu64, &btime) == 1) + { + fclose(f); + return btime * SECOND_TO_NS; + } + } + fclose(f); + ASSERT(false); + return 0; +} + +static void scap_get_bpf_stats_enabled(scap_machine_info* machine_info) +{ + machine_info->flags &= ~PPM_BPF_STATS_ENABLED; + FILE* f; + if((f = fopen("/proc/sys/kernel/bpf_stats_enabled", "r"))) + { + uint32_t bpf_stats_enabled = 0; + if(fscanf(f, "%u", &bpf_stats_enabled) == 1) + { + if (bpf_stats_enabled != 0) + { + machine_info->flags |= PPM_BPF_STATS_ENABLED; + } + } + fclose(f); + } +} + +static void scap_gethostname(char* buf, size_t size) +{ + char *env_hostname = getenv(SCAP_HOSTNAME_ENV_VAR); + if(env_hostname != NULL) + { + snprintf(buf, size, "%s", env_hostname); + } + else + { + gethostname(buf, size); + } +} + +int32_t scap_os_get_machine_info(scap_machine_info* machine_info, char* lasterr) +{ + machine_info->num_cpus = sysconf(_SC_NPROCESSORS_ONLN); + machine_info->memory_size_bytes = (uint64_t)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE); + scap_gethostname(machine_info->hostname, sizeof(machine_info->hostname)); + machine_info->boot_ts_epoch = scap_linux_get_host_boot_time_ns(lasterr); + if(machine_info->boot_ts_epoch == 0) + { + return SCAP_FAILURE; + } + scap_get_bpf_stats_enabled(machine_info); + + return SCAP_SUCCESS; +} + diff --git a/userspace/libscap/linux/scap_procs.c b/userspace/libscap/linux/scap_procs.c index 8b0d233e91..777f9fa2ff 100644 --- a/userspace/libscap/linux/scap_procs.c +++ b/userspace/libscap/linux/scap_procs.c @@ -388,7 +388,7 @@ int32_t scap_proc_fill_pidns_start_ts(char* error, struct scap_threadinfo* tinfo snprintf(proc_cmdline_pidns, sizeof(proc_cmdline_pidns), "%sroot/proc/1/cmdline", procdirname); if(stat(proc_cmdline_pidns, &targetstat) == 0) { - tinfo->pidns_init_start_ts = targetstat.st_ctim.tv_sec * (uint64_t) SECOND_TO_NS + targetstat.st_ctim.tv_nsec; + tinfo->pidns_init_start_ts = targetstat.st_ctim.tv_sec * SECOND_TO_NS + targetstat.st_ctim.tv_nsec; return SCAP_SUCCESS; } else @@ -480,8 +480,8 @@ int32_t scap_proc_fill_exe_ino_ctime_mtime(char* error, struct scap_threadinfo* if(stat(exetarget, &targetstat) == 0) { tinfo->exe_ino = targetstat.st_ino; - tinfo->exe_ino_ctime = targetstat.st_ctim.tv_sec * (uint64_t) SECOND_TO_NS + targetstat.st_ctim.tv_nsec; - tinfo->exe_ino_mtime = targetstat.st_mtim.tv_sec * (uint64_t) SECOND_TO_NS + targetstat.st_mtim.tv_nsec; + tinfo->exe_ino_ctime = targetstat.st_ctim.tv_sec * SECOND_TO_NS + targetstat.st_ctim.tv_nsec; + tinfo->exe_ino_mtime = targetstat.st_mtim.tv_sec * SECOND_TO_NS + targetstat.st_mtim.tv_nsec; } return SCAP_SUCCESS; @@ -822,7 +822,7 @@ static int32_t scap_proc_add_from_proc(struct scap_linux_platform* linux_platfor snprintf(proc_cmdline, sizeof(proc_cmdline), "%scmdline", dir_name); if(stat(proc_cmdline, &dirstat) == 0) { - tinfo->clone_ts = dirstat.st_ctim.tv_sec * (uint64_t) SECOND_TO_NS + dirstat.st_ctim.tv_nsec; + tinfo->clone_ts = dirstat.st_ctim.tv_sec * SECOND_TO_NS + dirstat.st_ctim.tv_nsec; } // If tid is different from pid, assume this is a thread and that the FDs are shared, and set the diff --git a/userspace/libscap/macos/scap_machine_info.c b/userspace/libscap/macos/scap_machine_info.c new file mode 100644 index 0000000000..8fc66b52ae --- /dev/null +++ b/userspace/libscap/macos/scap_machine_info.c @@ -0,0 +1,123 @@ +/* +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 "scap_machine_info.h" +#include "scap_os_machine_info.h" +#include "scap_limits.h" +#include "scap_assert.h" +#include "scap.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#define US_TO_NS 1000ULL + +// https://stackoverflow.com/questions/3269321/osx-programmatically-get-uptime +static uint64_t scap_macos_get_host_boot_time_ns() +{ + struct timeval boottime; + size_t len = sizeof(boottime); + int mib[2] = { CTL_KERN, KERN_BOOTTIME }; + if(sysctl(mib, 2, &boottime, &len, NULL, 0) < 0) + { + return 0; + } + + return (boottime.tv_sec * SECOND_TO_NS) + + (boottime.tv_usec * US_TO_NS); +} + +void scap_os_get_agent_info(scap_agent_info* agent_info) +{ + agent_info->start_ts_epoch = 0; + agent_info->start_time = 0; + + /* Info 1: + * + * unix time in nsec of our startup time + */ + { + // https://stackoverflow.com/questions/31603885/get-process-creation-date-time-in-osx-with-c-c/31605649 + struct kinfo_proc info; + int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, (int)getpid() }; + size_t len = sizeof info; + memset(&info, 0, len); + int rc = sysctl(mib, 4, &info, &len, NULL, 0); + if(rc == 0) + { + struct timeval tv = info.kp_proc.p_starttime; + if(tv.tv_sec != 0) + { + agent_info->start_ts_epoch = (tv.tv_sec * SECOND_TO_NS) + + (tv.tv_usec * US_TO_NS); + } + } + } + + /* Info 2: + * + * our startup time in seconds since boot + */ + if(agent_info->start_ts_epoch != 0) + { + uint64_t boot_time_ns = scap_macos_get_host_boot_time_ns(); + agent_info->start_time = (agent_info->start_ts_epoch - boot_time_ns) / (1.0 * SECOND_TO_NS); + } + + /* Info 3: + * + * Kernel release `uname -r` of the machine the agent is running on. + */ + + struct utsname uts; + uname(&uts); + snprintf(agent_info->uname_r, sizeof(agent_info->uname_r), "%s", uts.release); +} + +static void scap_gethostname(char* buf, size_t size) +{ + char *env_hostname = getenv(SCAP_HOSTNAME_ENV_VAR); + if(env_hostname != NULL) + { + snprintf(buf, size, "%s", env_hostname); + } + else + { + gethostname(buf, size); + } +} + +int32_t scap_os_get_machine_info(scap_machine_info* machine_info, char* lasterr) +{ + machine_info->num_cpus = sysconf(_SC_NPROCESSORS_ONLN); + machine_info->memory_size_bytes = (uint64_t)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE); + scap_gethostname(machine_info->hostname, sizeof(machine_info->hostname)); + machine_info->boot_ts_epoch = scap_macos_get_host_boot_time_ns(); + if(machine_info->boot_ts_epoch == 0) + { + return SCAP_FAILURE; + } + + return SCAP_SUCCESS; +} + diff --git a/userspace/libscap/scap.c b/userspace/libscap/scap.c index f9b66807b0..2a63c6565d 100644 --- a/userspace/libscap/scap.c +++ b/userspace/libscap/scap.c @@ -29,6 +29,16 @@ limitations under the License. #ifdef __linux__ #include "scap_linux_platform.h" +#else +// 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. +struct scap_platform* scap_linux_alloc_platform() +{ + return NULL; +} #endif const char* scap_getlasterr(scap_t* handle) @@ -171,7 +181,14 @@ int32_t scap_init(scap_t* handle, scap_open_args* oargs) if(strcmp(engine_name, SOURCE_PLUGIN_ENGINE) == 0) { vtable = &scap_source_plugin_engine; - platform = scap_generic_alloc_platform(); + if(oargs->mode == SCAP_MODE_LIVE) + { + platform = scap_linux_alloc_platform(); + } + else + { + platform = scap_generic_alloc_platform(); + } } #endif diff --git a/userspace/libscap/scap_machine_info.h b/userspace/libscap/scap_machine_info.h index 58c262be16..4827b82cc2 100644 --- a/userspace/libscap/scap_machine_info.h +++ b/userspace/libscap/scap_machine_info.h @@ -56,7 +56,7 @@ typedef struct _scap_machine_info typedef struct _scap_agent_info { uint64_t start_ts_epoch; ///< Agent start timestamp, stat /proc/self/cmdline approach, unit: epoch in nanoseconds - double start_time; ///< /proc/self/stat start_time divided by HZ, unit: seconds + double start_time; ///< /proc/self/stat start_time divided by HZ, unit: seconds since boot char uname_r[128]; ///< Kernel release `uname -r` } scap_agent_info; diff --git a/userspace/libscap/scap_os_machine_info.h b/userspace/libscap/scap_os_machine_info.h new file mode 100644 index 0000000000..451e683e97 --- /dev/null +++ b/userspace/libscap/scap_os_machine_info.h @@ -0,0 +1,32 @@ +/* +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 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _scap_agent_info scap_agent_info; +typedef struct _scap_machine_info scap_machine_info; + +void scap_os_get_agent_info(scap_agent_info* agent_info); +int32_t scap_os_get_machine_info(scap_machine_info* machine_info, char* lasterr); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/userspace/libscap/scap_platform.c b/userspace/libscap/scap_platform.c index 4c91466d65..f0cc6b5568 100644 --- a/userspace/libscap/scap_platform.c +++ b/userspace/libscap/scap_platform.c @@ -21,9 +21,18 @@ limitations under the License. #include "scap.h" #include "scap-int.h" +#include "scap_os_machine_info.h" static int32_t scap_generic_init_platform(struct scap_platform* platform, char* lasterr, struct scap_open_args* oargs) { + memset(&platform->m_machine_info, 0, sizeof(platform->m_machine_info)); + 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); + platform->m_proclist.m_proc_callback = oargs->proc_callback; platform->m_proclist.m_proc_callback_context = oargs->proc_callback_context; platform->m_proclist.m_proclist = NULL; diff --git a/userspace/libscap/win32/gettimeofday.h b/userspace/libscap/win32/gettimeofday.h index 7138222f30..b8dcf35e9c 100644 --- a/userspace/libscap/win32/gettimeofday.h +++ b/userspace/libscap/win32/gettimeofday.h @@ -20,20 +20,21 @@ limitations under the License. #include #include -static inline uint64_t get_timestamp_ns() +static inline uint64_t ft_to_epoch_nsec(FILETIME* ft) { - uint64_t ts; - - FILETIME ft; static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL); - - GetSystemTimePreciseAsFileTime(&ft); - - uint64_t ftl = (((uint64_t)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; + uint64_t ftl = (((uint64_t)ft->dwHighDateTime) << 32) + ft->dwLowDateTime; ftl -= EPOCH; - ts = ftl * 100; - + uint64_t ts = ftl * 100; return ts; } +static inline uint64_t get_timestamp_ns() +{ + FILETIME ft; + GetSystemTimePreciseAsFileTime(&ft); + + return ft_to_epoch_nsec(&ft); +} + diff --git a/userspace/libscap/win32/scap_machine_info.c b/userspace/libscap/win32/scap_machine_info.c new file mode 100644 index 0000000000..99a724df70 --- /dev/null +++ b/userspace/libscap/win32/scap_machine_info.c @@ -0,0 +1,152 @@ +/* +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. + +*/ + +#ifndef _UNICODE +#define _UNICODE +#endif + +#include "scap_machine_info.h" +#include "scap_os_machine_info.h" +#include "scap_limits.h" +#include "scap_assert.h" +#include "scap.h" +#include "gettimeofday.h" + +#include +#include +#include +#include + +#define MSEC_TO_NS 1000000 + +typedef LONG (WINAPI * RtlGetVersionProc) (OSVERSIONINFOEX *); +#ifndef STATUS_SUCCESS +#define STATUS_SUCCESS 0 +#endif + +// https://stackoverflow.com/questions/10853985/programmatically-getting-system-boot-up-time-in-c-windows +static uint64_t scap_windows_get_host_boot_time_ns() +{ + return GetTickCount64() * MSEC_TO_NS; +} + +void scap_os_get_agent_info(scap_agent_info* agent_info) +{ + agent_info->start_ts_epoch = 0; + agent_info->start_time = 0; + + /* Info 1: + * + * unix time in nsec of our startup time + */ + { + FILETIME creation_time, exit_time, kernel_time, user_time; + if(GetProcessTimes(GetCurrentProcess(), &creation_time, &exit_time, &kernel_time, &user_time)) + { + agent_info->start_ts_epoch = ft_to_epoch_nsec(&creation_time); + } + } + + /* Info 2: + * + * our startup time in seconds since boot + */ + if(agent_info->start_ts_epoch != 0) + { + uint64_t boot_time_ns = scap_windows_get_host_boot_time_ns(); + agent_info->start_time = (agent_info->start_ts_epoch - boot_time_ns) / (1.0 * SECOND_TO_NS); + } + + /* Info 3: + * + * Kernel release `uname -r` of the machine the agent is running on. + */ + { + OSVERSIONINFOEX win_version_info = {0}; + RtlGetVersionProc RtlGetVersionP = 0; + LONG version_status = -1; // Any nonzero value should work. + + /* + * We want the major and minor Windows version along with other + * information. GetVersionEx provides this, but is deprecated. + * We use RtlGetVersion instead, which requires a bit of extra + * effort. + */ + + HMODULE ntdll_module = LoadLibrary(_T("ntdll.dll")); + if(ntdll_module) + { + RtlGetVersionP = (RtlGetVersionProc) GetProcAddress(ntdll_module, "RtlGetVersion"); + win_version_info.dwOSVersionInfoSize = sizeof(win_version_info); + version_status = RtlGetVersionP(&win_version_info); + FreeLibrary(ntdll_module); + } + + if (version_status != STATUS_SUCCESS) + { + snprintf(agent_info->uname_r, sizeof(agent_info->uname_r), "Windows (unknown version)"); + } + else + { + // more space than the absolute worst case of UTF16->UTF8 conversion + char utf8_servicepack[sizeof(win_version_info.szCSDVersion) * 2] = {0}; + + // ... but if it still gets truncated, be sad for a while and move on + // (our output buffer is finite, anyway) + WideCharToMultiByte(CP_UTF8, 0, win_version_info.szCSDVersion, -1, utf8_servicepack, sizeof(utf8_servicepack), NULL, NULL); + + snprintf(agent_info->uname_r, sizeof(agent_info->uname_r), "Windows %lu.%lu%s%s, build %lu", + win_version_info.dwMajorVersion, win_version_info.dwMinorVersion, + utf8_servicepack[0] != '\0' ? " " : "", + utf8_servicepack, + win_version_info.dwBuildNumber); + } + } +} + +static void scap_gethostname(char* buf, size_t size) +{ + char *env_hostname = getenv(SCAP_HOSTNAME_ENV_VAR); + if(env_hostname != NULL) + { + snprintf(buf, size, "%s", env_hostname); + } + else + { + gethostname(buf, size); + } +} + +int32_t scap_os_get_machine_info(scap_machine_info* machine_info, char* lasterr) +{ + SYSTEM_INFO si; + GetSystemInfo(&si); + machine_info->num_cpus = si.dwNumberOfProcessors; + + ULONGLONG mem_kb; + GetPhysicallyInstalledSystemMemory(&mem_kb); + machine_info->memory_size_bytes = mem_kb * 1024; + + scap_gethostname(machine_info->hostname, sizeof(machine_info->hostname)); + machine_info->boot_ts_epoch = scap_windows_get_host_boot_time_ns(); + if(machine_info->boot_ts_epoch == 0) + { + return SCAP_FAILURE; + } + + return SCAP_SUCCESS; +} diff --git a/userspace/libsinsp/sinsp.cpp b/userspace/libsinsp/sinsp.cpp index 1c689c3bc9..a1790e145e 100644 --- a/userspace/libsinsp/sinsp.cpp +++ b/userspace/libsinsp/sinsp.cpp @@ -645,9 +645,9 @@ void sinsp::open_savefile(const std::string& filename, int fd) open_common(&oargs); } -void sinsp::open_plugin(const std::string& plugin_name, const std::string& plugin_open_params) +void sinsp::open_plugin(const std::string& plugin_name, const std::string& plugin_open_params, scap_mode_t mode) { - scap_open_args oargs = factory_open_args(SOURCE_PLUGIN_ENGINE, SCAP_MODE_PLUGIN); + scap_open_args oargs = factory_open_args(SOURCE_PLUGIN_ENGINE, mode); struct scap_source_plugin_engine_params params; set_input_plugin(plugin_name, plugin_open_params); params.input_plugin = &m_input_plugin->as_scap_source(); diff --git a/userspace/libsinsp/sinsp.h b/userspace/libsinsp/sinsp.h index e2dc09ff4d..284b89399e 100644 --- a/userspace/libsinsp/sinsp.h +++ b/userspace/libsinsp/sinsp.h @@ -226,7 +226,8 @@ class SINSP_PUBLIC sinsp : public capture_stats_source virtual void open_udig(); 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); + virtual void open_plugin(const std::string& plugin_name, const std::string& plugin_open_params, + scap_mode_t mode = SCAP_MODE_PLUGIN); 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/events_evt.ut.cpp b/userspace/libsinsp/test/events_evt.ut.cpp index 8ba17f1b8e..5221f6a6a2 100644 --- a/userspace/libsinsp/test/events_evt.ut.cpp +++ b/userspace/libsinsp/test/events_evt.ut.cpp @@ -69,7 +69,7 @@ TEST_F(sinsp_with_test_input, event_hostname) add_default_init_thread(); - open_inspector(SCAP_MODE_LIVE); + open_inspector(); sinsp_evt *evt = NULL; /* Toy event example from a previous test. */