Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new(scap): extend scap machine info, new agent info (new metrics 1/n) #880

Merged
merged 11 commits into from
Mar 28, 2023
Merged
5 changes: 5 additions & 0 deletions driver/flags_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -645,3 +645,8 @@ const struct ppm_name_value epoll_create1_flags[] = {
{"EPOLL_CLOEXEC", PPM_EPOLL_CLOEXEC},
{0, 0},
};

const struct ppm_name_value machine_info_flags[] = {
{"BPF_STATS_ENABLED", PPM_BPF_STATS_ENABLED},
{0, 0},
};
5 changes: 5 additions & 0 deletions driver/ppm_events_public.h
Original file line number Diff line number Diff line change
Expand Up @@ -2005,4 +2005,9 @@ struct ppm_event_entry {
#define RW_MAX_SNAPLEN PPM_MAX_ARG_SIZE
#define RW_MAX_FULLCAPTURE_PORT_SNAPLEN 16000

/*
* machine_info flags.
*/
#define PPM_BPF_STATS_ENABLED (1 << 0)

#endif /* EVENTS_PUBLIC_H_ */
6 changes: 6 additions & 0 deletions userspace/libscap/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ if(NOT DEFINED SCAP_HOST_ROOT_ENV_VAR_NAME)
endif()
add_definitions(-DSCAP_HOST_ROOT_ENV_VAR_NAME="${SCAP_HOST_ROOT_ENV_VAR_NAME}")

if(NOT DEFINED SCAP_HOSTNAME_ENV_VAR)
set(SCAP_HOSTNAME_ENV_VAR "SCAP_HOSTNAME")
endif()
add_definitions(-DSCAP_HOSTNAME_ENV_VAR="${SCAP_HOSTNAME_ENV_VAR}")

if (DEFINED SCAP_BPF_PROGS_TAIL_CALLED_MAX)
add_definitions(-DBPF_PROGS_TAIL_CALLED_MAX=${SCAP_BPF_PROGS_TAIL_CALLED_MAX})
endif()
Expand All @@ -57,6 +62,7 @@ list(APPEND targetfiles
scap_savefile.c
scap_procs.c
scap_userlist.c
scap_machine_agent.c
scap_suppress.c)

if(CMAKE_SYSTEM_NAME MATCHES "Linux")
Expand Down
25 changes: 25 additions & 0 deletions userspace/libscap/scap-int.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ struct scap
uint64_t m_evtcnt;
scap_addrlist* m_addrlist;
scap_machine_info m_machine_info;
scap_agent_info m_agent_info;
scap_userlist* m_userlist;
struct ppm_proclist_info* m_driver_procinfo;
uint32_t m_fd_lookup_limit;
Expand Down Expand Up @@ -122,6 +123,30 @@ int32_t scap_check_suppressed(struct scap_suppress *suppress, scap_evt *pevent,
int32_t scap_procfs_get_threadlist(struct scap_engine_handle engine, struct ppm_proclist_info **procinfo_p, char *lasterr);
int32_t scap_os_getpid_global(struct scap_engine_handle engine, int64_t *pid, char* error);

//
// Get hostname.
//
// Supports env variable lookup for cloud native integrations
// where the hostname can be equivalent to the Kubernetes pod name.
// Customizable over cmake setup SCAP_HOSTNAME_ENV_VAR.
//
void scap_gethostname(scap_t* handle);

//
// Retrieve agent info.
//
void scap_retrieve_agent_info(scap_t* handle);

//
// Retrieve machine info.
//
void scap_retrieve_machine_info(scap_t* handle, uint64_t boot_time);

//
// Check if kernel.bpf_stats_enabled is set.
//
void scap_get_bpf_stats_enabled(scap_t* handle);

//
// Useful stuff
//
Expand Down
76 changes: 36 additions & 40 deletions userspace/libscap/scap.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,13 @@ int32_t scap_init_live_int(scap_t* handle, scap_open_args* oargs, const struct s
// Extract machine information
//

handle->m_machine_info.num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
handle->m_machine_info.memory_size_bytes = (uint64_t)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE);
gethostname(handle->m_machine_info.hostname, sizeof(handle->m_machine_info.hostname) / sizeof(handle->m_machine_info.hostname[0]));
handle->m_machine_info.boot_ts_epoch = boot_time;
handle->m_machine_info.reserved2 = 0;
handle->m_machine_info.reserved3 = 0;
handle->m_machine_info.reserved4 = 0;
handle->m_driver_procinfo = NULL;
handle->m_fd_lookup_limit = 0;
scap_retrieve_machine_info(handle, boot_time);

//
// Extract agent information
//

scap_retrieve_agent_info(handle);

//
// Create the interface list
Expand Down Expand Up @@ -200,15 +198,13 @@ int32_t scap_init_udig_int(scap_t* handle, scap_open_args* oargs)
// Extract machine information
//

handle->m_machine_info.num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
handle->m_machine_info.memory_size_bytes = (uint64_t)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE);
gethostname(handle->m_machine_info.hostname, sizeof(handle->m_machine_info.hostname) / sizeof(handle->m_machine_info.hostname[0]));
handle->m_machine_info.boot_ts_epoch = boot_time;
handle->m_machine_info.reserved2 = 0;
handle->m_machine_info.reserved3 = 0;
handle->m_machine_info.reserved4 = 0;
handle->m_driver_procinfo = NULL;
handle->m_fd_lookup_limit = 0;
scap_retrieve_machine_info(handle, boot_time);

//
// Extract agent information
//

scap_retrieve_agent_info(handle);

//
// Create the interface list
Expand Down Expand Up @@ -446,21 +442,19 @@ int32_t scap_init_nodriver_int(scap_t* handle, scap_open_args* oargs)
// Extract machine information
//

handle->m_machine_info.num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
handle->m_machine_info.memory_size_bytes = (uint64_t)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE);
gethostname(handle->m_machine_info.hostname, sizeof(handle->m_machine_info.hostname) / sizeof(handle->m_machine_info.hostname[0]));
handle->m_machine_info.boot_ts_epoch = boot_time;
handle->m_machine_info.reserved2 = 0;
handle->m_machine_info.reserved3 = 0;
handle->m_machine_info.reserved4 = 0;
handle->m_driver_procinfo = NULL;

scap_retrieve_machine_info(handle, boot_time);
if(!engine_params || !engine_params->full_proc_scan)
{
handle->m_minimal_scan = true;
handle->m_fd_lookup_limit = SCAP_NODRIVER_MAX_FD_LOOKUP; // fd lookup is limited here because is very expensive
}

//
// Extract agent information
//

scap_retrieve_agent_info(handle);

//
// Create the interface list
//
Expand Down Expand Up @@ -527,21 +521,15 @@ int32_t scap_init_plugin_int(scap_t* handle, scap_open_args* oargs)
//
// Extract machine information
//
#ifdef _WIN32
handle->m_machine_info.num_cpus = 0;
handle->m_machine_info.memory_size_bytes = 0;
#else
handle->m_machine_info.num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
handle->m_machine_info.memory_size_bytes = (uint64_t)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE);
#endif
gethostname(handle->m_machine_info.hostname, sizeof(handle->m_machine_info.hostname) / sizeof(handle->m_machine_info.hostname[0]));
handle->m_machine_info.boot_ts_epoch = 0; // plugin does not need boot_ts_epoch
handle->m_machine_info.reserved2 = 0;
handle->m_machine_info.reserved3 = 0;
handle->m_machine_info.reserved4 = 0;
handle->m_driver_procinfo = NULL;
scap_retrieve_machine_info(handle, (uint64_t)0);
handle->m_fd_lookup_limit = SCAP_NODRIVER_MAX_FD_LOOKUP; // fd lookup is limited here because is very expensive

//
// Extract agent information
//

scap_retrieve_agent_info(handle);

if((rc = handle->m_vtable->init(handle, oargs)) != SCAP_SUCCESS)
{
return rc;
Expand Down Expand Up @@ -972,6 +960,14 @@ const scap_machine_info* scap_get_machine_info(scap_t* handle)
}
}

//
// Get the agent information
//
const scap_agent_info* scap_get_agent_info(scap_t* handle)
{
return (const scap_agent_info*)&handle->m_agent_info;
}

int32_t scap_set_snaplen(scap_t* handle, uint32_t snaplen)
{
if(handle->m_vtable)
Expand Down
1 change: 1 addition & 0 deletions userspace/libscap/scap.def
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ EXPORTS
scap_proc_free
scap_start_capture
scap_get_machine_info
scap_get_agent_info
scap_stop_dropping_mode
scap_start_dropping_mode
scap_get_user_list
Expand Down
23 changes: 21 additions & 2 deletions userspace/libscap/scap.h
Original file line number Diff line number Diff line change
Expand Up @@ -324,11 +324,21 @@ typedef struct _scap_machine_info
uint64_t max_pid; ///< Highest PID number on this machine
char hostname[128]; ///< The machine hostname
uint64_t boot_ts_epoch; ///< Host boot ts in nanoseconds (epoch)
uint64_t reserved2; ///< reserved for future use
uint64_t flags; ///< flags
uint64_t reserved3; ///< reserved for future use
uint64_t reserved4; ///< reserved for future use
uint64_t reserved4; ///< reserved for future use, note: because of scap file captures needs to remain uint64_t, use flags if possible
}scap_machine_info;

/*!
\brief Agent information, not intended for scap file use
*/
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
incertum marked this conversation as resolved.
Show resolved Hide resolved
char uname_r[128]; ///< Kernel release `uname -r`
}scap_agent_info;

/*!
\brief Interface address type
*/
Expand Down Expand Up @@ -839,6 +849,15 @@ const char* scap_get_ppm_sc_name(ppm_sc_code sc);
*/
const scap_machine_info* scap_get_machine_info(scap_t* handle);

/*!
\brief Get generic agent information

\return The pointer to a \ref scap_agent_info structure containing the information.

\note for live captures only.
*/
const scap_agent_info* scap_get_agent_info(scap_t* handle);

/*!
\brief Set the capture snaplen, i.e. the maximum size an event parameter can
reach before the driver starts truncating it.
Expand Down
135 changes: 135 additions & 0 deletions userspace/libscap/scap_machine_agent.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/*
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 <stdio.h>
#ifdef _WIN32
#include <Winsock2.h>
#else
#include <unistd.h>
#include <inttypes.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/utsname.h>
#endif // _WIN32

#include "scap.h"
#include "scap-int.h"

#define SECOND_TO_NS 1000000000

void scap_gethostname(scap_t* handle)
{
char *env_hostname = getenv(SCAP_HOSTNAME_ENV_VAR);
if(env_hostname != NULL)
{
snprintf(handle->m_machine_info.hostname, sizeof(handle->m_machine_info.hostname), "%s", env_hostname);
}
else
{
gethostname(handle->m_machine_info.hostname, sizeof(handle->m_machine_info.hostname) / sizeof(handle->m_machine_info.hostname[0]));
}
}

void scap_retrieve_machine_info(scap_t* handle, uint64_t boot_time)
{
#ifdef _WIN32
handle->m_machine_info.num_cpus = 0;
handle->m_machine_info.memory_size_bytes = 0;
#else
handle->m_machine_info.num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
handle->m_machine_info.memory_size_bytes = (uint64_t)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE);
#endif
scap_gethostname(handle);
handle->m_machine_info.boot_ts_epoch = boot_time;
scap_get_bpf_stats_enabled(handle);
handle->m_machine_info.reserved3 = 0;
handle->m_machine_info.reserved4 = 0;
handle->m_driver_procinfo = NULL;
handle->m_fd_lookup_limit = 0;
}

void scap_retrieve_agent_info(scap_t* handle)
{
handle->m_agent_info.start_ts_epoch = 0;
handle->m_agent_info.start_time = 0;
#ifdef __linux__

/* Info 1:
*
* Get epoch timestamp based on procfs stat, only used for (constant) agent start time reporting.
*/
struct stat st = {0};
char path[256];
snprintf(path, sizeof(path), "/proc/%d/cmdline", getpid());
if(stat(path, &st) == 0)
{
handle->m_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.
*/
char proc_stat[256];
FILE* f;
snprintf(proc_stat, sizeof(proc_stat), "/proc/%d/stat", getpid());
if((f = fopen(proc_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)
{
ASSERT(false);
}
#endif
if(fscanf(f, "%*d %*s %*c %*d %*d %*d %*d %*d %*lu %*lu %*lu %*lu %*lu %*llu %*llu %*llu %*llu %*d %*d %*d %*lu %llu", &stat_start_time))
{
handle->m_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(handle->m_agent_info.uname_r, sizeof(handle->m_agent_info.uname_r), "%s", uts.release);
#endif
}

void scap_get_bpf_stats_enabled(scap_t* handle)
{
#ifdef __linux__
handle->m_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;
fscanf(f, "%u", &bpf_stats_enabled);
fclose(f);
if (bpf_stats_enabled != 0)
{
handle->m_machine_info.flags |= PPM_BPF_STATS_ENABLED;
}
}
#endif
}
Loading