diff --git a/userspace/libscap/clock_helpers.h b/userspace/libscap/clock_helpers.h new file mode 100644 index 0000000000..320f178821 --- /dev/null +++ b/userspace/libscap/clock_helpers.h @@ -0,0 +1,81 @@ +/* +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. + +*/ +#ifndef __CLOCK_HELPERS_H +#define __CLOCK_HELPERS_H + +#define SCAP_GET_CUR_TS_MS_CONTEXT_INIT ((uint64_t)0) +#define SCAP_GET_CUR_TS_MS_CONTEXT_ERROR_FLAG ((uint64_t)0x8000000000000000) +#define SCAP_GET_CUR_TS_MS_CONTEXT_PREV_VALUE_MASK ((uint64_t)0x7fffffffffffffff) + +#define S_TO_MS(_sec) (((uint64_t)_sec) * (uint64_t)1000) +#define NS_TO_MS(_ns) (((uint64_t)_ns) / ((uint64_t)(1000 * 1000))) + +/** + * Return monotonically increasing time in ms. + * Caller initializes context to SCAP_GET_CUR_TS_MS_CONTEXT_INIT, + * Function uses and updates context, to recognize and handle the + * following cases: + * - failed clock_gettime() system call + * - non-monotonic behavior of CLOCK_MONOTONIC + * - time values that cannot be represented in uint64_t number of msec + */ +static __always_inline uint64_t scap_get_monotonic_ts_ms(uint64_t* context) +{ + // Record previously reported time; will be 0 for first call. + uint64_t prev_time = ((*context) & SCAP_GET_CUR_TS_MS_CONTEXT_PREV_VALUE_MASK); + + // If context indicates error already detected, just return the + // last reported time + if ((*context) & SCAP_GET_CUR_TS_MS_CONTEXT_ERROR_FLAG) + { + return prev_time; + } + + // Fetch current monotonic time from kernel + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts)) + { + // System call failed. + // Set error flag + *context |= SCAP_GET_CUR_TS_MS_CONTEXT_ERROR_FLAG; + + // Return previously reported time, now frozen + return prev_time; + } + + // Form new time + uint64_t new_time = S_TO_MS(ts.tv_sec) + NS_TO_MS(ts.tv_nsec); + + // Check for overflow or non-monotonic behavior + if ((new_time & SCAP_GET_CUR_TS_MS_CONTEXT_ERROR_FLAG) || + (new_time < prev_time)) + { + // System call failed. + // Set error flag + *context |= SCAP_GET_CUR_TS_MS_CONTEXT_ERROR_FLAG; + + // Return previously reported time, now frozen + return prev_time; + } + + // New time looks OK. + // Store it into the context, and return it. + *context = new_time; + return new_time; +} + +#endif /* __CLOCK_HELPERS_H */ diff --git a/userspace/libscap/debug_log_helpers.h b/userspace/libscap/debug_log_helpers.h new file mode 100644 index 0000000000..e87720cf88 --- /dev/null +++ b/userspace/libscap/debug_log_helpers.h @@ -0,0 +1,41 @@ +/* +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. + +*/ +#ifndef __DEBUG_LOG_HELPERS_H +#define __DEBUG_LOG_HELPERS_H + +#include "scap.h" +#include + +/** + * If debug_log_fn has been established in the handle, call that function + * to log a debug message. + */ +static void scap_debug_log(scap_t* handle, const char* fmt, ...) +{ + if (handle->m_debug_log_fn != NULL) + { + char buf[256]; + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + (*handle->m_debug_log_fn)(buf); + } +} + +#endif /* __DEBUG_LOG_HELPERS_H */ diff --git a/userspace/libscap/scap-int.h b/userspace/libscap/scap-int.h index 7b95ca542f..7ef013420e 100644 --- a/userspace/libscap/scap-int.h +++ b/userspace/libscap/scap-int.h @@ -121,6 +121,13 @@ struct scap // If the schema version is unavailable for whatever reason, // it's equivalent to version 0.0.0 uint64_t m_schema_version; + + // /proc scan parameters + uint64_t m_proc_scan_timeout_ms; + uint64_t m_proc_scan_log_interval_ms; + + // Function which may be called to log a debug event + void(*m_debug_log_fn)(const char* msg); }; typedef enum ppm_dumper_type @@ -195,7 +202,7 @@ int32_t scap_add_fd_to_proc_table(scap_t* handle, scap_threadinfo* pi, scap_fdin // Remove the given fd from the process table of the process pointed by pi void scap_fd_remove(scap_t* handle, scap_threadinfo* pi, int64_t fd); // read the file descriptors for a given process directory -int32_t scap_fd_scan_fd_dir(scap_t* handle, char * procdir, scap_threadinfo* pi, struct scap_ns_socket_list** sockets_by_ns, char *error); +int32_t scap_fd_scan_fd_dir(scap_t* handle, char * procdir, scap_threadinfo* pi, struct scap_ns_socket_list** sockets_by_ns, uint64_t* num_fds_ret, char *error); // scan fd information for a specific thread from engine vtable. src_tinfo is a pointer to a threadinfo returned by the engine int32_t scap_fd_scan_vtable(scap_t *handle, const scap_threadinfo *src_tinfo, scap_threadinfo *dst_tinfo, char *error); // read tcp or udp sockets from the proc filesystem diff --git a/userspace/libscap/scap.c b/userspace/libscap/scap.c index aa9159a5f4..32e2e313a0 100644 --- a/userspace/libscap/scap.c +++ b/userspace/libscap/scap.c @@ -96,7 +96,10 @@ scap_t* scap_open_udig_int(char *error, int32_t *rc, proc_entry_callback proc_callback, void* proc_callback_context, bool import_users, - const char **suppressed_comms) + const char **suppressed_comms, + void(*debug_log_fn)(const char* msg), + uint64_t proc_scan_timeout_ms, + uint64_t proc_scan_log_interval_ms) { snprintf(error, SCAP_LASTERR_SIZE, "udig capture not supported on %s", PLATFORM_NAME); *rc = SCAP_NOT_SUPPORTED; @@ -125,6 +128,10 @@ scap_t* scap_open_live_int(char *error, int32_t *rc, scap_open_args* oargs) // Preliminary initializations // handle->m_mode = SCAP_MODE_LIVE; + handle->m_debug_log_fn = oargs->debug_log_fn; + handle->m_proc_scan_timeout_ms = oargs->proc_scan_timeout_ms; + handle->m_proc_scan_log_interval_ms = oargs->proc_scan_log_interval_ms; + if(strncmp(oargs->engine_name, BPF_ENGINE, BPF_ENGINE_LEN) == 0) { handle->m_vtable = &scap_bpf_engine; @@ -277,7 +284,10 @@ scap_t* scap_open_udig_int(char *error, int32_t *rc, proc_entry_callback proc_callback, void* proc_callback_context, bool import_users, - const char **suppressed_comms) + const char **suppressed_comms, + void(*debug_log_fn)(const char* msg), + uint64_t proc_scan_timeout_ms, + uint64_t proc_scan_log_interval_ms) { char filename[SCAP_MAX_PATH_SIZE]; scap_t* handle = NULL; @@ -297,6 +307,9 @@ scap_t* scap_open_udig_int(char *error, int32_t *rc, // Preliminary initializations // handle->m_mode = SCAP_MODE_LIVE; + handle->m_debug_log_fn = debug_log_fn; + handle->m_proc_scan_timeout_ms = proc_scan_timeout_ms; + handle->m_proc_scan_log_interval_ms = proc_scan_log_interval_ms; handle->m_ncpus = 1; handle->m_vtable = &scap_udig_engine; @@ -488,6 +501,10 @@ scap_t* scap_open_test_input_int(char *error, int32_t *rc, scap_open_args *oargs handle->m_proclist.m_proc_callback_context = oargs->proc_callback_context; handle->m_proclist.m_proclist = NULL; + handle->m_debug_log_fn = oargs->debug_log_fn; + handle->m_proc_scan_timeout_ms = oargs->proc_scan_timeout_ms; + handle->m_proc_scan_log_interval_ms = oargs->proc_scan_log_interval_ms; + if ((*rc = copy_comms(handle, oargs->suppressed_comms)) != SCAP_SUCCESS) { scap_close(handle); @@ -577,6 +594,10 @@ scap_t* scap_open_gvisor_int(char *error, int32_t *rc, scap_open_args *oargs) handle->m_proclist.m_proc_callback_context = oargs->proc_callback_context; handle->m_proclist.m_proclist = NULL; + handle->m_debug_log_fn = oargs->debug_log_fn; + handle->m_proc_scan_timeout_ms = oargs->proc_scan_timeout_ms; + handle->m_proc_scan_log_interval_ms = oargs->proc_scan_log_interval_ms; + if ((*rc = copy_comms(handle, oargs->suppressed_comms)) != SCAP_SUCCESS) { scap_close(handle); @@ -614,7 +635,7 @@ scap_t* scap_open_offline_int(scap_open_args* oargs, int* rc, char* error) // // Allocate the handle // - handle = (scap_t*)malloc(sizeof(scap_t)); + handle = (scap_t*)calloc(sizeof(scap_t), 1); if(!handle) { snprintf(error, SCAP_LASTERR_SIZE, "error allocating the scap_t structure"); @@ -689,7 +710,10 @@ scap_t* scap_open_offline_int(scap_open_args* oargs, int* rc, char* error) scap_t* scap_open_nodriver_int(char *error, int32_t *rc, proc_entry_callback proc_callback, void* proc_callback_context, - bool import_users) + bool import_users, + void(*debug_log_fn)(const char* msg), + uint64_t proc_scan_timeout_ms, + uint64_t proc_scan_log_interval_ms) { #if !defined(HAS_CAPTURE) snprintf(error, SCAP_LASTERR_SIZE, "live capture not supported on %s", PLATFORM_NAME); @@ -702,7 +726,7 @@ scap_t* scap_open_nodriver_int(char *error, int32_t *rc, // // Allocate the handle // - handle = (scap_t*)malloc(sizeof(scap_t)); + handle = (scap_t*)calloc(sizeof(scap_t), 1); if(!handle) { snprintf(error, SCAP_LASTERR_SIZE, "error allocating the scap_t structure"); @@ -729,6 +753,10 @@ scap_t* scap_open_nodriver_int(char *error, int32_t *rc, handle->m_proclist.m_proc_callback_context = proc_callback_context; handle->m_proclist.m_proclist = NULL; + handle->m_debug_log_fn = debug_log_fn; + handle->m_proc_scan_timeout_ms = proc_scan_timeout_ms; + handle->m_proc_scan_log_interval_ms = proc_scan_log_interval_ms; + // // Extract machine information // @@ -849,6 +877,10 @@ scap_t* scap_open_plugin_int(char *error, int32_t *rc, scap_open_args* oargs) handle->m_proclist.m_proc_callback_context = NULL; handle->m_proclist.m_proclist = NULL; + handle->m_debug_log_fn = oargs->debug_log_fn; + handle->m_proc_scan_timeout_ms = oargs->proc_scan_timeout_ms; + handle->m_proc_scan_log_interval_ms = oargs->proc_scan_log_interval_ms; + // // Extract machine information // @@ -909,7 +941,10 @@ scap_t* scap_open(scap_open_args* oargs, char *error, int32_t *rc) return scap_open_udig_int(error, rc, oargs->proc_callback, oargs->proc_callback_context, oargs->import_users, - oargs->suppressed_comms); + oargs->suppressed_comms, + oargs->debug_log_fn, + oargs->proc_scan_timeout_ms, + oargs->proc_scan_log_interval_ms); } else if(strncmp(engine_name, GVISOR_ENGINE, GVISOR_ENGINE_LEN) == 0) { @@ -929,7 +964,10 @@ scap_t* scap_open(scap_open_args* oargs, char *error, int32_t *rc) { return scap_open_nodriver_int(error, rc, oargs->proc_callback, oargs->proc_callback_context, - oargs->import_users); + oargs->import_users, + oargs->debug_log_fn, + oargs->proc_scan_timeout_ms, + oargs->proc_scan_log_interval_ms); } else if(strncmp(engine_name, SOURCE_PLUGIN_ENGINE, SOURCE_PLUGIN_ENGINE_LEN) == 0) { diff --git a/userspace/libscap/scap.h b/userspace/libscap/scap.h index 869851d774..39367d66a3 100644 --- a/userspace/libscap/scap.h +++ b/userspace/libscap/scap.h @@ -126,6 +126,19 @@ struct iovec; // #define DEFAULT_DRIVER_BUFFER_BYTES_DIM 8 * 1024 * 1024 +// +// Value for proc_scan_timeout_ms field in scap_open_args, to specify +// that scan should run to completion without any timeout imposed +// +#define SCAP_PROC_SCAN_TIMEOUT_NONE 0 + +// +// Value for proc_scan_log_interval_ms field in scap_open_args, to specify +// that no progress logging should be performed +// +#define SCAP_PROC_SCAN_LOG_NONE 0 + + /*! \brief Statistics about an in progress capture */ @@ -316,6 +329,12 @@ typedef struct { UT_hash_handle hh; ///< makes this structure hashable } scap_mountinfo; +typedef void (*proc_entry_callback)(void* context, + scap_t* handle, + int64_t tid, + scap_threadinfo* tinfo, + scap_fdinfo* fdinfo); + // // The following stuff is byte aligned because we save it to disk. // diff --git a/userspace/libscap/scap_fds.c b/userspace/libscap/scap_fds.c index f4b1e58b92..9c632f84a7 100644 --- a/userspace/libscap/scap_fds.c +++ b/userspace/libscap/scap_fds.c @@ -1579,7 +1579,7 @@ char * decode_st_mode(struct stat* sb) // // Scan the directory containing the fd's of a proc /proc/x/fd // -int32_t scap_fd_scan_fd_dir(scap_t *handle, char *procdir, scap_threadinfo *tinfo, struct scap_ns_socket_list **sockets_by_ns, char *error) +int32_t scap_fd_scan_fd_dir(scap_t *handle, char *procdir, scap_threadinfo *tinfo, struct scap_ns_socket_list **sockets_by_ns, uint64_t* num_fds_ret, char *error) { DIR *dir_p; struct dirent *dir_entry_p; @@ -1594,6 +1594,11 @@ int32_t scap_fd_scan_fd_dir(scap_t *handle, char *procdir, scap_threadinfo *tinf ssize_t r; uint16_t fd_added = 0; + if (num_fds_ret != NULL) + { + *num_fds_ret = 0; + } + snprintf(fd_dir_name, SCAP_MAX_PATH_SIZE, "%sfd", procdir); dir_p = opendir(fd_dir_name); if(dir_p == NULL) @@ -1717,6 +1722,12 @@ int32_t scap_fd_scan_fd_dir(scap_t *handle, char *procdir, scap_threadinfo *tinf } } closedir(dir_p); + + if (num_fds_ret != NULL) + { + *num_fds_ret = fd_added; + } + return res; } diff --git a/userspace/libscap/scap_open.h b/userspace/libscap/scap_open.h index a89ee14ff4..020377cf6b 100644 --- a/userspace/libscap/scap_open.h +++ b/userspace/libscap/scap_open.h @@ -98,6 +98,9 @@ extern "C" // values via scap_suppress_events_comm(). interesting_ppm_sc_set ppm_sc_of_interest; ///< syscalls of interest. interesting_tp_set tp_of_interest; ///< tp of interest. If left empty, no tracepoints will be attached + void(*debug_log_fn)(const char* msg); //< Function which SCAP may use to log a debug message + uint64_t proc_scan_timeout_ms; //< Timeout in msec, after which so-far-successful scan of /proc should be cut short with success return + uint64_t proc_scan_log_interval_ms; //< Interval for logging progress messages from /proc scan void* engine_params; ///< engine-specific params. } scap_open_args; diff --git a/userspace/libscap/scap_procs.c b/userspace/libscap/scap_procs.c index fc858ce5da..085a6e075d 100644 --- a/userspace/libscap/scap_procs.c +++ b/userspace/libscap/scap_procs.c @@ -39,6 +39,8 @@ limitations under the License. #include "scap-int.h" #include "scap_engines.h" #include "engine/kmod/kmod.h" +#include "clock_helpers.h" +#include "debug_log_helpers.h" #if defined(CYGWING_AGENT) || defined(_WIN32) #include @@ -669,7 +671,7 @@ static int32_t scap_proc_fill_exe_writable(scap_t* handle, struct scap_threadinf // // Add a process to the list by parsing its entry under /proc // -static int32_t scap_proc_add_from_proc(scap_t* handle, uint32_t tid, char* procdirname, struct scap_ns_socket_list** sockets_by_ns, scap_threadinfo** procinfo, char *error) +static int32_t scap_proc_add_from_proc(scap_t* handle, uint32_t tid, char* procdirname, struct scap_ns_socket_list** sockets_by_ns, scap_threadinfo** procinfo, uint64_t* num_fds_ret, char *error) { char dir_name[256]; char target_name[SCAP_MAX_PATH_SIZE]; @@ -1040,7 +1042,7 @@ static int32_t scap_proc_add_from_proc(scap_t* handle, uint32_t tid, char* procd // if(tinfo->pid == tinfo->tid) { - res = scap_fd_scan_fd_dir(handle, dir_name, tinfo, sockets_by_ns, error); + res = scap_fd_scan_fd_dir(handle, dir_name, tinfo, sockets_by_ns, num_fds_ret, error); } if(free_tinfo) @@ -1066,7 +1068,7 @@ static int32_t scap_proc_read_thread(scap_t* handle, char* procdirname, uint64_t sockets_by_ns = (void*)-1; } - res = scap_proc_add_from_proc(handle, tid, procdirname, &sockets_by_ns, pi, add_error); + res = scap_proc_add_from_proc(handle, tid, procdirname, &sockets_by_ns, pi, NULL, add_error); if(res != SCAP_SUCCESS) { snprintf(error, SCAP_LASTERR_SIZE, "cannot add proc tid = %"PRIu64", dirname = %s, error=%s", tid, procdirname, add_error); @@ -1092,6 +1094,9 @@ static int32_t _scap_proc_scan_proc_dir_impl(scap_t* handle, char* procdirname, int32_t res = SCAP_SUCCESS; char childdir[SCAP_MAX_PATH_SIZE]; + uint64_t num_procs_processed = 0; + uint64_t total_num_fds = 0; + uint64_t last_tid_processed = 0; struct scap_ns_socket_list* sockets_by_ns = NULL; dir_p = opendir(procdirname); @@ -1103,8 +1108,36 @@ static int32_t _scap_proc_scan_proc_dir_impl(scap_t* handle, char* procdirname, return SCAP_NOTFOUND; } - while((dir_entry_p = readdir(dir_p)) != NULL) + // Do timing tracking only if: + // - this is the top-level call (parenttid == -1) + // - one or both of the timing parameters is configured to non-zero + bool do_timing = (parenttid == -1) && + ((handle->m_proc_scan_timeout_ms != SCAP_PROC_SCAN_TIMEOUT_NONE) || + (handle->m_proc_scan_log_interval_ms != SCAP_PROC_SCAN_LOG_NONE)); + uint64_t monotonic_ts_context = SCAP_GET_CUR_TS_MS_CONTEXT_INIT; + uint64_t start_ts_ms = 0; + uint64_t last_log_ts_ms = 0; + uint64_t last_proc_ts_ms = 0; + uint64_t cur_ts_ms = 0; + uint64_t min_proc_time_ms = UINT64_MAX; + uint64_t max_proc_time_ms = 0; + + if (do_timing) + { + start_ts_ms = scap_get_monotonic_ts_ms(&monotonic_ts_context); + last_log_ts_ms = start_ts_ms; + last_proc_ts_ms = start_ts_ms; + } + + bool timeout_expired = false; + while (!timeout_expired) { + dir_entry_p = readdir(dir_p); + if (dir_entry_p == NULL) + { + break; + } + if(strspn(dir_entry_p->d_name, "0123456789") != strlen(dir_entry_p->d_name)) { continue; @@ -1116,7 +1149,8 @@ static int32_t _scap_proc_scan_proc_dir_impl(scap_t* handle, char* procdirname, tid = atoi(dir_entry_p->d_name); // - // Skip the main thread entry + // If this is a recursive call for tasks of a parent process, + // skip the main thread entry // if(parenttid != -1 && tid == parenttid) { @@ -1142,7 +1176,8 @@ static int32_t _scap_proc_scan_proc_dir_impl(scap_t* handle, char* procdirname, // // We have a process that needs to be explored // - res = scap_proc_add_from_proc(handle, tid, procdirname, &sockets_by_ns, NULL, add_error); + uint64_t num_fds_this_proc; + res = scap_proc_add_from_proc(handle, tid, procdirname, &sockets_by_ns, NULL, &num_fds_this_proc, add_error); if(res != SCAP_SUCCESS) { // @@ -1174,6 +1209,92 @@ static int32_t _scap_proc_scan_proc_dir_impl(scap_t* handle, char* procdirname, break; } } + + // TID successfully processed. + last_tid_processed = tid; + num_procs_processed++; + total_num_fds += num_fds_this_proc; + + // After successful processing of a process at the top level, + // perform timing processing if configured. + if (do_timing) + { + cur_ts_ms = scap_get_monotonic_ts_ms(&monotonic_ts_context); + uint64_t total_elapsed_time_ms = cur_ts_ms - start_ts_ms; + + uint64_t this_proc_elapsed_time_ms = cur_ts_ms - last_proc_ts_ms; + last_proc_ts_ms = cur_ts_ms; + + if (this_proc_elapsed_time_ms < min_proc_time_ms) + { + min_proc_time_ms = this_proc_elapsed_time_ms; + } + if (this_proc_elapsed_time_ms > max_proc_time_ms) + { + max_proc_time_ms = this_proc_elapsed_time_ms; + } + + if (handle->m_proc_scan_log_interval_ms != SCAP_PROC_SCAN_LOG_NONE) + { + uint64_t log_elapsed_time_ms = cur_ts_ms - last_log_ts_ms; + if (log_elapsed_time_ms >= handle->m_proc_scan_log_interval_ms) + { + scap_debug_log(handle, + "scap_proc_scan: %ld proc in %ld ms, avg=%ld/min=%ld/max=%ld, last pid %ld, num_fds %ld", + num_procs_processed, + total_elapsed_time_ms, + (total_elapsed_time_ms / (uint64_t)num_procs_processed), + min_proc_time_ms, + max_proc_time_ms, + last_tid_processed, + total_num_fds); + last_log_ts_ms = cur_ts_ms; + } + } + + if (handle->m_proc_scan_timeout_ms != SCAP_PROC_SCAN_TIMEOUT_NONE) + { + if (total_elapsed_time_ms >= handle->m_proc_scan_timeout_ms) + { + timeout_expired = true; + } + } + } + } + + if (do_timing) + { + cur_ts_ms = scap_get_monotonic_ts_ms(&monotonic_ts_context); + uint64_t total_elapsed_time_ms = cur_ts_ms - start_ts_ms; + uint64_t avg_proc_time_ms = (num_procs_processed != 0) ? + (total_elapsed_time_ms / num_procs_processed) : 0; + + if (timeout_expired) + { + scap_debug_log(handle, + "scap_proc_scan TIMEOUT (%ld ms): %ld proc in %ld ms, avg=%ld/min=%ld/max=%ld, last pid %ld, num_fds %ld", + handle->m_proc_scan_timeout_ms, + num_procs_processed, + total_elapsed_time_ms, + avg_proc_time_ms, + min_proc_time_ms, + max_proc_time_ms, + last_tid_processed, + total_num_fds); + } + else if ((handle->m_proc_scan_log_interval_ms != SCAP_PROC_SCAN_LOG_NONE) && + (num_procs_processed != 0)) + { + scap_debug_log(handle, + "scap_proc_scan DONE: %ld proc in %ld ms, avg=%ld/min=%ld/max=%ld, last pid %ld, num_fds %ld", + num_procs_processed, + total_elapsed_time_ms, + avg_proc_time_ms, + min_proc_time_ms, + max_proc_time_ms, + last_tid_processed, + total_num_fds); + } } closedir(dir_p); @@ -1498,7 +1619,7 @@ int32_t scap_update_suppressed(scap_t *handle, if(*suppressed && stid == NULL) { - stid = (scap_tid *) malloc(sizeof(scap_tid)); + stid = (scap_tid *) calloc(sizeof(scap_tid), 1); stid->tid = tid; int32_t uth_status = SCAP_SUCCESS; diff --git a/userspace/libsinsp/sinsp.cpp b/userspace/libsinsp/sinsp.cpp index 5536c9973a..57d6244c79 100644 --- a/userspace/libsinsp/sinsp.cpp +++ b/userspace/libsinsp/sinsp.cpp @@ -129,6 +129,9 @@ sinsp::sinsp(bool static_container, const std::string &static_id, const std::str m_self_pid = getpid(); #endif + m_proc_scan_timeout_ms = SCAP_PROC_SCAN_TIMEOUT_NONE; + m_proc_scan_log_interval_ms = SCAP_PROC_SCAN_LOG_NONE; + uint32_t evlen = sizeof(scap_evt) + 2 * sizeof(uint16_t) + 2 * sizeof(uint64_t); m_meinfo.m_piscapevt = (scap_evt*)new char[evlen]; m_meinfo.m_piscapevt->type = PPME_PROCINFO_E; @@ -550,6 +553,10 @@ void sinsp::open_common(scap_open_args* oargs) add_suppressed_comms(oargs); + oargs->debug_log_fn = &sinsp_scap_debug_log_fn; + oargs->proc_scan_timeout_ms = m_proc_scan_timeout_ms; + oargs->proc_scan_log_interval_ms = m_proc_scan_log_interval_ms; + int32_t scap_rc = 0; m_h = scap_open(oargs, error, &scap_rc); if(m_h == NULL) @@ -2588,6 +2595,16 @@ void sinsp::set_thread_timeout_s(uint32_t val) m_thread_timeout_ns = (uint64_t)val * ONE_SECOND_IN_NS; } +void sinsp::set_proc_scan_timeout_ms(uint64_t val) +{ + m_proc_scan_timeout_ms = val; +} + +void sinsp::set_proc_scan_log_interval_ms(uint64_t val) +{ + m_proc_scan_log_interval_ms = val; +} + /////////////////////////////////////////////////////////////////////////////// // Note: this is defined here so we can inline it in sinso::next /////////////////////////////////////////////////////////////////////////////// diff --git a/userspace/libsinsp/sinsp.h b/userspace/libsinsp/sinsp.h index 79a5307a3a..951f687e01 100644 --- a/userspace/libsinsp/sinsp.h +++ b/userspace/libsinsp/sinsp.h @@ -396,6 +396,19 @@ class SINSP_PUBLIC sinsp : public capture_stats_source, public wmi_handle_source */ void set_thread_timeout_s(uint32_t val); + /*! + * \brief sets the max amount of time that the initial scan of /proc should execute, + * after which a so-far-successful scan should be stopped and success returned. + * Value of SCAP_PROC_SCAN_TIMEOUT_NONE (default) means run to completion. + */ + void set_proc_scan_timeout_ms(uint64_t val); + + /*! + * \brief sets the interval for logging progress messages during initial scan of /proc. + * Value of SCAP_PROC_SCAN_LOGUT_NONE (default) means no logging. + */ + void set_proc_scan_log_interval_ms(uint64_t val); + /*! \brief Start writing the captured events to file. @@ -1419,6 +1432,12 @@ VISIBILITY_PRIVATE int64_t m_self_pid; #endif + // + // /proc scan parameters + // + uint64_t m_proc_scan_timeout_ms; + uint64_t m_proc_scan_log_interval_ms; + // Any thread with a comm in this set will not have its events // returned in sinsp::next() std::set m_suppressed_comms; diff --git a/userspace/libsinsp/utils.cpp b/userspace/libsinsp/utils.cpp index 01fbd8576d..b9de4e73aa 100644 --- a/userspace/libsinsp/utils.cpp +++ b/userspace/libsinsp/utils.cpp @@ -1894,3 +1894,11 @@ unsigned int read_num_possible_cpus(void) return possible_cpus; } + +/////////////////////////////////////////////////////////////////////////////// +// Log helper +/////////////////////////////////////////////////////////////////////////////// +void sinsp_scap_debug_log_fn(const char* msg) +{ + g_logger.log(msg, sinsp_logger::SEV_DEBUG); +} diff --git a/userspace/libsinsp/utils.h b/userspace/libsinsp/utils.h index 9ac1d2ad2d..a85615dc9b 100644 --- a/userspace/libsinsp/utils.h +++ b/userspace/libsinsp/utils.h @@ -430,3 +430,8 @@ inline void hash_combine(std::size_t &seed, const T& val) { seed ^= std::hash()(val) + 0x9e3779b9 + (seed<<6) + (seed>>2); } + +/////////////////////////////////////////////////////////////////////////////// +// Log helpers +/////////////////////////////////////////////////////////////////////////////// +void sinsp_scap_debug_log_fn(const char* msg);