diff --git a/userspace/libsinsp/filterchecks.cpp b/userspace/libsinsp/filterchecks.cpp index 51d2a26ff6..19a30ef466 100644 --- a/userspace/libsinsp/filterchecks.cpp +++ b/userspace/libsinsp/filterchecks.cpp @@ -1905,10 +1905,12 @@ const filtercheck_field_info sinsp_filter_check_thread_fields[] = {PT_UINT64, EPF_NONE, PF_DEC, "proc.cmdnargs", "Number of cmd args", "The number of cmd args."}, {PT_UINT64, EPF_NONE, PF_DEC, "proc.cmdlenargs", "Total Count of Chars in cmd args", "The total count of characters / length of all cmd args combined excluding whitespaces."}, {PT_INT64, EPF_NONE, PF_ID, "proc.pvpid", "Parent Virtual Process ID", "the id of the parent process generating the event as seen from its current PID namespace."}, - {PT_INT64, EPF_NONE, PF_DEC, "proc.exe_ino", "Inode number of executable image file on disk", "The inode number of the executable image file on disk. Can be directly correlated with file operation event's field fd.ino as alternative to using file paths."}, + {PT_INT64, EPF_NONE, PF_DEC, "proc.exe_ino", "Inode number of executable image file on disk", "The inode number of the executable image file on disk. Can be correlated with fd.ino."}, {PT_ABSTIME, EPF_NONE, PF_DEC, "proc.exe_ino.ctime", "Last status change time (ctime - epoch ns) of exe file on disk", "Last status change time (ctime - epoch nanoseconds) of executable image file on disk (inode->ctime). Time is changed by writing or by setting inode information e.g. owner, group, link count, mode etc."}, {PT_ABSTIME, EPF_NONE, PF_DEC, "proc.exe_ino.mtime", "Last modification time (mtime - epoch ns) of exe file on disk", "Last modification time (mtime - epoch nanoseconds) of executable image file on disk (inode->mtime). Time is changed by file modifications, e.g. by mknod, truncate, utime, write of more than zero bytes etc. For tracking changes in owner, group, link count or mode, use proc.exe_ino.ctime instead."}, - {PT_ABSTIME, EPF_NONE, PF_DEC, "proc.exe_ino.ctime_duration_proc_start", "Time delta in ns - proc clone ts minus ctime exe file", "Time delta between process clone ts and ctime exe file in ns, aka duration of time passed after modifying the status of the executable image and then spawning a new process using the changed executable image."}, + {PT_ABSTIME, EPF_NONE, PF_DEC, "proc.exe_ino.ctime_duration_proc_start", "Number of nanoseconds between ctime exe file and proc clone ts", "Number of nanoseconds between modifying status of executable image and spawning a new process using the changed executable image."}, + {PT_ABSTIME, EPF_NONE, PF_DEC, "proc.exe_ino.ctime_duration_pidns_start", "Number of nanoseconds between pidns start ts and ctime exe file", "Number of nanoseconds between pid namespace start ts and ctime exe file if pidns start predates ctime."}, + {PT_UINT64, EPF_NONE, PF_DEC, "proc.pidns_init_start_ts", "Start ts of pid namespace (epoch ns)", "Start ts (epoch ns) of pid namespace; approximate start ts of container if pid in container or start ts of host if pid in host namespace."}, }; sinsp_filter_check_thread::sinsp_filter_check_thread() @@ -2778,6 +2780,18 @@ uint8_t* sinsp_filter_check_thread::extract(sinsp_evt *evt, OUT uint32_t* len, b return NULL; } RETURN_EXTRACT_VAR(tinfo->m_exe_ino_ctime_duration_clone_ts); + case TYPE_EXE_INO_CTIME_DURATION_PIDNS_START: + if(tinfo->m_exe_ino_ctime_duration_pidns_start == 0) + { + return NULL; + } + RETURN_EXTRACT_VAR(tinfo->m_exe_ino_ctime_duration_pidns_start); + case TYPE_PIDNS_INIT_START_TS: + if(tinfo->m_pidns_init_start_ts == 0) + { + return NULL; + } + RETURN_EXTRACT_VAR(tinfo->m_pidns_init_start_ts); default: ASSERT(false); return NULL; @@ -6215,7 +6229,9 @@ const filtercheck_field_info sinsp_filter_check_container_fields[] = {PT_CHARBUF, EPF_NONE, PF_NA, "container.image.digest", "Registry Digest", "the container image registry digest (e.g. sha256:d977378f890d445c15e51795296e4e5062f109ce6da83e0a355fc4ad8699d27)."}, {PT_CHARBUF, EPF_NONE, PF_NA, "container.healthcheck", "Health Check", "The container's health check. Will be the null value (\"N/A\") if no healthcheck configured, \"NONE\" if configured but explicitly not created, and the healthcheck command line otherwise"}, {PT_CHARBUF, EPF_NONE, PF_NA, "container.liveness_probe", "Liveness", "The container's liveness probe. Will be the null value (\"N/A\") if no liveness probe configured, the liveness probe command line otherwise"}, - {PT_CHARBUF, EPF_NONE, PF_NA, "container.readiness_probe", "Readiness", "The container's readiness probe. Will be the null value (\"N/A\") if no readiness probe configured, the readiness probe command line otherwise"} + {PT_CHARBUF, EPF_NONE, PF_NA, "container.readiness_probe", "Readiness", "The container's readiness probe. Will be the null value (\"N/A\") if no readiness probe configured, the readiness probe command line otherwise"}, + {PT_UINT64, EPF_NONE, PF_DEC, "container.start_ts", "Container start ts (epoch in ns)", "Container start ts (epoch in ns) based on proc.pidns_init_start_ts."}, + {PT_RELTIME, EPF_NONE, PF_DEC, "container.duration", "Number of nanoseconds since the container start ts", "Number of nanoseconds since the container start ts."}, }; sinsp_filter_check_container::sinsp_filter_check_container() @@ -6695,7 +6711,20 @@ uint8_t* sinsp_filter_check_container::extract(sinsp_evt *evt, OUT uint32_t* len m_tstr = "NONE"; RETURN_EXTRACT_STRING(m_tstr); } - + case TYPE_CONTAINER_START_TS: + if(tinfo->m_container_id.empty() || tinfo->m_pidns_init_start_ts == 0) + { + return NULL; + } + RETURN_EXTRACT_VAR(tinfo->m_pidns_init_start_ts); + case TYPE_CONTAINER_DURATION: + if(tinfo->m_container_id.empty() || tinfo->m_clone_ts == 0) + { + return NULL; + } + m_s64val = evt->get_ts() - tinfo->m_pidns_init_start_ts; + ASSERT(m_s64val > 0); + RETURN_EXTRACT_VAR(m_s64val); default: ASSERT(false); break; diff --git a/userspace/libsinsp/filterchecks.h b/userspace/libsinsp/filterchecks.h index e8abe4d057..b8c3242616 100644 --- a/userspace/libsinsp/filterchecks.h +++ b/userspace/libsinsp/filterchecks.h @@ -388,6 +388,8 @@ class sinsp_filter_check_thread : public sinsp_filter_check TYPE_EXE_INO_CTIME = 57, TYPE_EXE_INO_MTIME = 58, TYPE_EXE_INO_CTIME_DURATION_CLONE_TS = 59, + TYPE_EXE_INO_CTIME_DURATION_PIDNS_START = 60, + TYPE_PIDNS_INIT_START_TS = 61, }; sinsp_filter_check_thread(); @@ -802,6 +804,8 @@ class sinsp_filter_check_container : public sinsp_filter_check TYPE_CONTAINER_HEALTHCHECK, TYPE_CONTAINER_LIVENESS_PROBE, TYPE_CONTAINER_READINESS_PROBE, + TYPE_CONTAINER_START_TS, + TYPE_CONTAINER_DURATION, }; sinsp_filter_check_container(); @@ -817,6 +821,7 @@ class sinsp_filter_check_container : public sinsp_filter_check uint32_t m_u32val; int32_t m_argid; string m_argstr; + int64_t m_s64val; }; // diff --git a/userspace/libsinsp/parsers.cpp b/userspace/libsinsp/parsers.cpp index 3a102d925d..c72c5b8756 100644 --- a/userspace/libsinsp/parsers.cpp +++ b/userspace/libsinsp/parsers.cpp @@ -1625,6 +1625,17 @@ void sinsp_parser::parse_clone_exit(sinsp_evt *evt) // tinfo->m_clone_ts = evt->get_ts(); + // + // Get pid namespace start ts - convert monotonic time in ns to epoch ts + // + + if(evt->get_num_params() > 20) + { + parinfo = evt->get_param(20); + ASSERT(parinfo->m_len == sizeof(uint64_t)); + tinfo->m_pidns_init_start_ts = *(uint64_t *)parinfo->m_val + m_inspector->m_boot_ts_epoch; + } + // // Add the new thread to the table // @@ -2104,6 +2115,11 @@ void sinsp_parser::parse_execve_exit(sinsp_evt *evt) { evt->m_tinfo->m_exe_ino_ctime_duration_clone_ts = evt->m_tinfo->m_clone_ts - evt->m_tinfo->m_exe_ino_ctime; } + + if(evt->m_tinfo->m_pidns_init_start_ts != 0 && (evt->m_tinfo->m_exe_ino_ctime > evt->m_tinfo->m_pidns_init_start_ts)) + { + evt->m_tinfo->m_exe_ino_ctime_duration_pidns_start = evt->m_tinfo->m_exe_ino_ctime - evt->m_tinfo->m_pidns_init_start_ts; + } } // diff --git a/userspace/libsinsp/threadinfo.cpp b/userspace/libsinsp/threadinfo.cpp index af07448c9b..b9ec9385e9 100644 --- a/userspace/libsinsp/threadinfo.cpp +++ b/userspace/libsinsp/threadinfo.cpp @@ -75,6 +75,7 @@ void sinsp_threadinfo::init() m_pfminor = 0; m_vtid = -1; m_vpid = -1; + m_pidns_init_start_ts = 0; m_main_thread.reset(); m_lastevent_fd = 0; m_last_latency_entertime = 0; @@ -93,6 +94,7 @@ void sinsp_threadinfo::init() m_exe_ino_ctime = 0; m_exe_ino_mtime = 0; m_exe_ino_ctime_duration_clone_ts = 0; + m_exe_ino_ctime_duration_pidns_start = 0; memset(&m_user, 0, sizeof(scap_userinfo)); memset(&m_group, 0, sizeof(scap_groupinfo)); @@ -425,6 +427,7 @@ void sinsp_threadinfo::init(scap_threadinfo* pi) m_exe_ino_ctime = pi->exe_ino_ctime; m_exe_ino_mtime = pi->exe_ino_mtime; m_exe_ino_ctime_duration_clone_ts = pi->exe_ino_ctime_duration_clone_ts; + m_exe_ino_ctime_duration_pidns_start = pi->exe_ino_ctime_duration_pidns_start; m_vmsize_kb = pi->vmsize_kb; m_vmrss_kb = pi->vmrss_kb; @@ -434,6 +437,7 @@ void sinsp_threadinfo::init(scap_threadinfo* pi) m_nchilds = 0; m_vtid = pi->vtid; m_vpid = pi->vpid; + m_pidns_init_start_ts = pi->pidns_init_start_ts; m_clone_ts = pi->clone_ts; m_tty = pi->tty; m_category = CAT_NONE; diff --git a/userspace/libsinsp/threadinfo.h b/userspace/libsinsp/threadinfo.h index ef8fe098f7..37991ad6ae 100644 --- a/userspace/libsinsp/threadinfo.h +++ b/userspace/libsinsp/threadinfo.h @@ -300,6 +300,7 @@ class SINSP_PUBLIC sinsp_threadinfo uint64_t m_exe_ino_ctime; ///< executable inode ctime (last status change time) uint64_t m_exe_ino_mtime; ///< executable inode mtime (last modification time) uint64_t m_exe_ino_ctime_duration_clone_ts; ///< duration in ns between executable inode ctime (last status change time) and clone_ts + uint64_t m_exe_ino_ctime_duration_pidns_start; ///< duration in ns between pidns start ts and executable inode ctime (last status change time) if pidns start predates ctime uint64_t m_nchilds; ///< When this is 0 the process can be deleted uint32_t m_vmsize_kb; ///< total virtual memory (as kb). uint32_t m_vmrss_kb; ///< resident non-swapped memory (as kb). @@ -309,6 +310,7 @@ class SINSP_PUBLIC sinsp_threadinfo int64_t m_vtid; ///< The virtual id of this thread. int64_t m_vpid; ///< The virtual id of the process containing this thread. In single thread threads, this is equal to vtid. int64_t m_vpgid; // The virtual process group id, as seen from its pid namespace + uint64_t m_pidns_init_start_ts; ///