Skip to content

Commit

Permalink
new(libsinsp): add aexe filter and display option
Browse files Browse the repository at this point in the history
This new option provides new opportunities to write
filter expressions for many use cases.

Signed-off-by: Melissa Kilby <[email protected]>
  • Loading branch information
incertum authored and poiana committed Mar 7, 2023
1 parent 6f38d89 commit 600edf6
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 1 deletion.
133 changes: 132 additions & 1 deletion userspace/libsinsp/filterchecks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1877,6 +1877,8 @@ const filtercheck_field_info sinsp_filter_check_thread_fields[] =
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.pcmdline", "Parent Command Line", "the full command line (proc.name + proc.args) of the parent of the process generating the event."},
{PT_INT64, EPF_NONE, PF_ID, "proc.apid", "Ancestor Process ID", "the pid of one of the process ancestors. E.g. proc.apid[1] returns the parent pid, proc.apid[2] returns the grandparent pid, and so on. proc.apid[0] is the pid of the current process. proc.apid without arguments can be used in filters only and matches any of the process ancestors, e.g. proc.apid=1234."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.aname", "Ancestor Name", "the name (excluding the path) of one of the process ancestors. E.g. proc.aname[1] returns the parent name, proc.aname[2] returns the grandparent name, and so on. proc.aname[0] is the name of the current process. proc.aname without arguments can be used in filters only and matches any of the process ancestors, e.g. proc.aname=bash."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.pexe", "Parent First Argument", "The first command line argument (usually the executable name or a custom one) of the parent process."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.aexe", "Ancestor First Argument", "The first command line argument (usually the executable name or a custom one) of one of the process ancestors. E.g. proc.aexe[1] returns the parent first argument, proc.aexe[2] returns the grandparent first argument, and so on. proc.aexe[0] is the first argument of the current process. proc.aexe without arguments can be used in filters only and matches any of the process ancestors, e.g. proc.aexe endswith java."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.pexepath", "Parent Process Executable Path", "The full executable path of the parent process."},
{PT_CHARBUF, EPF_NONE, PF_NA, "proc.aexepath", "Ancestor Executable Path", "The full executable path of one of the process ancestors. E.g. proc.aexepath[1] returns the parent full executable path, proc.aexepath[2] returns the grandparent full executable path, and so on. proc.aexepath[0] is the full executable path of the current process. proc.aexepath without arguments can be used in filters only and matches any of the process ancestors, e.g. proc.aexepath contains java."},
{PT_INT64, EPF_NONE, PF_ID, "proc.loginshellid", "Login Shell ID", "the pid of the oldest shell among the ancestors of the current process, if there is one. This field can be used to separate different user sessions, and is useful in conjunction with chisels like spy_user."},
Expand Down Expand Up @@ -1953,7 +1955,7 @@ int32_t sinsp_filter_check_thread::extract_arg(string fldname, string val, OUT c
//
// 'arg' and 'resarg' are handled in a custom way
//
if(m_field_id == TYPE_APID || m_field_id == TYPE_ANAME || m_field_id == TYPE_AEXEPATH)
if(m_field_id == TYPE_APID || m_field_id == TYPE_ANAME || m_field_id == TYPE_AEXE || m_field_id == TYPE_AEXEPATH)
{
if(val[fldname.size()] == '[')
{
Expand Down Expand Up @@ -2070,6 +2072,29 @@ int32_t sinsp_filter_check_thread::parse_field_name(const char* str, bool alloc_

return res;
}
/* note: because of str similarity of proc.aexe to proc.aexepath, this needs to be placed after proc.aexepath*/
else if(STR_MATCH("proc.aexe"))
{
m_field_id = TYPE_AEXE;
m_field = &m_info.m_fields[m_field_id];

int32_t res = 0;

try
{
res = extract_arg("proc.aexe", val, NULL);
}
catch(...)
{
if(val == "proc.aexe")
{
m_argid = -1;
res = (int32_t)val.size();
}
}

return res;
}
else if(STR_MATCH("thread.totexectime"))
{
//
Expand Down Expand Up @@ -2522,6 +2547,52 @@ uint8_t* sinsp_filter_check_thread::extract(sinsp_evt *evt, OUT uint32_t* len, b
m_tstr = mt->get_comm();
RETURN_EXTRACT_STRING(m_tstr);
}
case TYPE_PEXE:
{
sinsp_threadinfo* ptinfo =
m_inspector->get_thread_ref(tinfo->m_ptid, false, true).get();

if(ptinfo != NULL)
{
m_tstr = ptinfo->get_exe();
RETURN_EXTRACT_STRING(m_tstr);
}
else
{
return NULL;
}
}
case TYPE_AEXE:
{
sinsp_threadinfo* mt = NULL;

if(tinfo->is_main_thread())
{
mt = tinfo;
}
else
{
mt = tinfo->get_main_thread();

if(mt == NULL)
{
return NULL;
}
}

for(int32_t j = 0; j < m_argid; j++)
{
mt = mt->get_parent_thread();

if(mt == NULL)
{
return NULL;
}
}

m_tstr = mt->get_exe();
RETURN_EXTRACT_STRING(m_tstr);
}
case TYPE_PEXEPATH:
{
sinsp_threadinfo* ptinfo =
Expand Down Expand Up @@ -3019,6 +3090,59 @@ bool sinsp_filter_check_thread::compare_full_aname(sinsp_evt *evt)
return found;
}

bool sinsp_filter_check_thread::compare_full_aexe(sinsp_evt *evt)
{
sinsp_threadinfo* tinfo = evt->get_thread_info();

if(tinfo == NULL)
{
return false;
}

sinsp_threadinfo* mt = NULL;

if(tinfo->is_main_thread())
{
mt = tinfo;
}
else
{
mt = tinfo->get_main_thread();

if(mt == NULL)
{
return false;
}
}

//
// No id specified, search in all of the ancestors
//
bool found = false;
sinsp_threadinfo::visitor_func_t visitor = [this, &found] (sinsp_threadinfo *pt)
{
bool res;

res = flt_compare(m_cmpop,
PT_CHARBUF,
(void*)pt->m_exe.c_str());

if(res == true)
{
found = true;

// Can stop traversing parent state
return false;
}

return true;
};

mt->traverse_parent_state(visitor);

return found;
}

bool sinsp_filter_check_thread::compare_full_aexepath(sinsp_evt *evt)
{
sinsp_threadinfo* tinfo = evt->get_thread_info();
Expand Down Expand Up @@ -3088,6 +3212,13 @@ bool sinsp_filter_check_thread::compare(sinsp_evt *evt)
return compare_full_aname(evt);
}
}
else if(m_field_id == TYPE_AEXE)
{
if(m_argid == -1)
{
return compare_full_aexe(evt);
}
}
else if(m_field_id == TYPE_AEXEPATH)
{
if(m_argid == -1)
Expand Down
3 changes: 3 additions & 0 deletions userspace/libsinsp/filterchecks.h
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,8 @@ class sinsp_filter_check_thread : public sinsp_filter_check
TYPE_PCMDLINE,
TYPE_APID,
TYPE_ANAME,
TYPE_PEXE,
TYPE_AEXE,
TYPE_PEXEPATH,
TYPE_AEXEPATH,
TYPE_LOGINSHELLID,
Expand Down Expand Up @@ -408,6 +410,7 @@ class sinsp_filter_check_thread : public sinsp_filter_check
uint8_t* extract_thread_cpu(sinsp_evt *evt, OUT uint32_t* len, sinsp_threadinfo* tinfo, bool extract_user, bool extract_system);
inline bool compare_full_apid(sinsp_evt *evt);
bool compare_full_aname(sinsp_evt *evt);
bool compare_full_aexe(sinsp_evt *evt);
bool compare_full_aexepath(sinsp_evt *evt);

int32_t m_argid;
Expand Down
10 changes: 10 additions & 0 deletions userspace/libsinsp/test/events_proc.ut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,16 +341,26 @@ TEST_F(sinsp_with_test_input, spawn_process)
// check that the pid is updated
ASSERT_EQ(get_field_as_string(evt, "proc.pid"), "20");
ASSERT_EQ(get_field_as_string(evt, "proc.apid[0]"), "20");
// check that the exe is updated (first arg given in this test setup is same as full exepath)
ASSERT_EQ(get_field_as_string(evt, "proc.exe"), "/bin/test-exe");
ASSERT_EQ(get_field_as_string(evt, "proc.aexe[0]"), "/bin/test-exe");
// check that the exepath is updated
ASSERT_EQ(get_field_as_string(evt, "proc.exepath"), "/bin/test-exe");
ASSERT_EQ(get_field_as_string(evt, "proc.aexepath[0]"), "/bin/test-exe");

// check that parent/ancestor info are taken from the parent process
ASSERT_EQ(get_field_as_string(evt, "proc.pname"), "init");

ASSERT_EQ(get_field_as_string(evt, "proc.pexepath"), "/sbin/init");
ASSERT_EQ(get_field_as_string(evt, "proc.aexepath[1]"), "/sbin/init");
ASSERT_FALSE(field_exists(evt, "proc.aexepath[2]"));
ASSERT_FALSE(field_exists(evt, "proc.aexepath[3]"));

ASSERT_EQ(get_field_as_string(evt, "proc.pexe"), "/sbin/init");
ASSERT_EQ(get_field_as_string(evt, "proc.aexe[1]"), "/sbin/init");
ASSERT_FALSE(field_exists(evt, "proc.aexe[2]"));
ASSERT_FALSE(field_exists(evt, "proc.aexe[3]"));

ASSERT_EQ(get_field_as_string(evt, "proc.aname[1]"), "init");
ASSERT_FALSE(field_exists(evt, "proc.aname[2]"));
ASSERT_EQ(get_field_as_string(evt, "proc.ppid"), "1");
Expand Down

0 comments on commit 600edf6

Please sign in to comment.