Skip to content

Commit

Permalink
update(anomalydetection): add lastevent_fd to tinfo + start fd / fs r…
Browse files Browse the repository at this point in the history
…elated filterchecks 2/n

Signed-off-by: Melissa Kilby <[email protected]>
  • Loading branch information
incertum committed Jul 14, 2024
1 parent 34ab66e commit 6d18a5b
Show file tree
Hide file tree
Showing 4 changed files with 243 additions and 24 deletions.
195 changes: 184 additions & 11 deletions plugins/anomalydetection/src/plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,8 @@ bool anomalydetection::init(falcosecurity::init_input& in)
// Accessor to falcosecurity/libs' thread table (process cache / core state engine)
m_thread_table = t.get_table(THREAD_TABLE_NAME, st::SS_PLUGIN_ST_INT64);
// Define accessors to falcosecurity/libs' thread table fields

/* proc related */
m_tid = m_thread_table.get_field(t.fields(), "tid", st::SS_PLUGIN_ST_INT64);
m_pid = m_thread_table.get_field(t.fields(), "pid", st::SS_PLUGIN_ST_INT64);
m_ptid = m_thread_table.get_field(t.fields(), "ptid", st::SS_PLUGIN_ST_INT64);
Expand All @@ -238,16 +240,37 @@ bool anomalydetection::init(falcosecurity::init_input& in)
m_exe_from_memfd = m_thread_table.get_field(t.fields(), "exe_from_memfd", st::SS_PLUGIN_ST_BOOL);
m_args = m_thread_table.get_field(t.fields(), "args", st::SS_PLUGIN_ST_TABLE);
m_args_value = t.get_subtable_field(m_thread_table, m_args, "value", st::SS_PLUGIN_ST_STRING);
// m_env = m_thread_table.get_field(t.fields(), "env", TBD);
m_container_id = m_thread_table.get_field(t.fields(), "container_id", st::SS_PLUGIN_ST_STRING);
// m_user = m_thread_table.get_field(t.fields(), "user", TBD);
// m_loginuser = m_thread_table.get_field(t.fields(), "loginuser", TBD);
// m_group = m_thread_table.get_field(t.fields(), "group", TBD);
m_env = m_thread_table.get_field(t.fields(), "env", st::SS_PLUGIN_ST_TABLE);
m_env_value = t.get_subtable_field(m_thread_table, m_env, "value", st::SS_PLUGIN_ST_STRING);
m_vtid = m_thread_table.get_field(t.fields(), "vtid", st::SS_PLUGIN_ST_INT64);
m_vpid = m_thread_table.get_field(t.fields(), "vpid", st::SS_PLUGIN_ST_INT64);
m_vpgid = m_thread_table.get_field(t.fields(), "vpgid", st::SS_PLUGIN_ST_INT64);
m_tty = m_thread_table.get_field(t.fields(), "tty", st::SS_PLUGIN_ST_UINT32);
m_cwd = m_thread_table.get_field(t.fields(), "cwd", st::SS_PLUGIN_ST_STRING);

/* user related */
// Not available until the next libs plugins API expansion

// m_user = m_thread_table.get_field(t.fields(), "user", TBD);
// m_loginuser = m_thread_table.get_field(t.fields(), "loginuser", TBD);
// m_group = m_thread_table.get_field(t.fields(), "group", TBD);

/* fd or fs related */
m_fds = m_thread_table.get_field(t.fields(), "file_descriptors", st::SS_PLUGIN_ST_TABLE);
m_fd_name_value = t.get_subtable_field(m_thread_table, m_fds, "name", st::SS_PLUGIN_ST_STRING);
m_fd_nameraw_value = t.get_subtable_field(m_thread_table, m_fds, "name_raw", st::SS_PLUGIN_ST_STRING);
m_fd_ino_value = t.get_subtable_field(m_thread_table, m_fds, "ino", st::SS_PLUGIN_ST_UINT64);
// m_fd_type_value = t.get_subtable_field(m_thread_table, m_fds, "type", st::SS_PLUGIN_ST_UINT32);
m_fd_flags_value = t.get_subtable_field(m_thread_table, m_fds, "flags", st::SS_PLUGIN_ST_UINT32);
m_fd_dev_value = t.get_subtable_field(m_thread_table, m_fds, "dev", st::SS_PLUGIN_ST_UINT32);
m_fd_mount_id_value = t.get_subtable_field(m_thread_table, m_fds, "mount_id", st::SS_PLUGIN_ST_UINT32);

/* container related */
m_container_id = m_thread_table.get_field(t.fields(), "container_id", st::SS_PLUGIN_ST_STRING);

/* Custom fields */
m_lastevent_fd_field = m_thread_table.add_field(
t.fields(), "lastevent_fd", st::SS_PLUGIN_ST_INT64);
}
catch(falcosecurity::plugin_exception e)
{
Expand Down Expand Up @@ -318,7 +341,8 @@ bool anomalydetection::extract(const falcosecurity::extract_fields_input& in)
{
auto& req = in.get_extract_request();
auto& tr = in.get_table_reader();
int64_t thread_id = in.get_event_reader().get_tid();
auto& evt = in.get_event_reader();
int64_t thread_id = evt.get_tid();
uint64_t count_min_sketch_estimate = 0;
std::string behavior_profile_concat_str;
auto index = req.get_arg_index();
Expand All @@ -330,14 +354,14 @@ bool anomalydetection::extract(const falcosecurity::extract_fields_input& in)
switch(req.get_field_id())
{
case ANOMALYDETECTION_COUNT_MIN_SKETCH_COUNT:
if(extract_filterchecks_concat_profile(thread_id, tr, m_behavior_profiles_fields[index], behavior_profile_concat_str))
if(extract_filterchecks_concat_profile(evt, tr, m_behavior_profiles_fields[index], behavior_profile_concat_str))
{
count_min_sketch_estimate = m_count_min_sketches[index].get()->estimate(behavior_profile_concat_str);
req.set_value(count_min_sketch_estimate, true);
}
return true;
case ANOMALYDETECTION_COUNT_MIN_SKETCH_BEHAVIOR_PROFILE_CONCAT_STR:
if(extract_filterchecks_concat_profile(thread_id, tr, m_behavior_profiles_fields[index], behavior_profile_concat_str))
if(extract_filterchecks_concat_profile(evt, tr, m_behavior_profiles_fields[index], behavior_profile_concat_str))
{
req.set_value(behavior_profile_concat_str, true);
}
Expand All @@ -354,17 +378,22 @@ bool anomalydetection::extract(const falcosecurity::extract_fields_input& in)
// Parse capability
//////////////////////////

bool anomalydetection::extract_filterchecks_concat_profile(int64_t thread_id, const falcosecurity::table_reader &tr, const std::vector<plugin_sinsp_filterchecks_field>& fields, std::string& behavior_profile_concat_str)
bool anomalydetection::extract_filterchecks_concat_profile(const falcosecurity::event_reader &evt, const falcosecurity::table_reader &tr, const std::vector<plugin_sinsp_filterchecks_field>& fields, std::string& behavior_profile_concat_str)
{
using st = falcosecurity::state_value_type;

int64_t thread_id = evt.get_tid();
auto thread_entry = m_thread_table.get_entry(tr, thread_id);
auto fd_table = m_thread_table.get_subtable(
tr, m_fds, thread_entry,
st::SS_PLUGIN_ST_INT64);

// Create a concatenated string formed out of each field per behavior profile
// No concept of null fields (instead its always an empty string) compared to libsinsp
for (const auto& field : fields)
{
std::string tstr;
uint64_t tuint64 = UINT64_MAX;
uint32_t tuint32 = UINT32_MAX;
int64_t tint64 = -1;
int64_t ptid = -1;
Expand Down Expand Up @@ -684,6 +713,61 @@ bool anomalydetection::extract_filterchecks_concat_profile(int64_t thread_id, co
m_comm.read_value(tr, *leader, tstr);
break;
}

//
// fd or fs related
//

case plugin_sinsp_filterchecks::TYPE_FDNAME:
{
switch(evt.get_type())
{
case PPME_SYSCALL_OPEN_X:
case PPME_SOCKET_ACCEPT_5_X:
case PPME_SOCKET_ACCEPT4_6_X:
case PPME_SYSCALL_CREAT_X:
{
m_lastevent_fd_field.read_value(tr, thread_entry, tint64);
auto fd_entry = fd_table.get_entry(tr, tint64);
m_fd_name_value.read_value(tr, fd_entry, tstr);
break;
}
case PPME_SOCKET_CONNECT_X:
{
break;
}
case PPME_SYSCALL_OPENAT_2_X:
case PPME_SYSCALL_OPENAT2_X:
{
m_lastevent_fd_field.read_value(tr, thread_entry, tint64);
auto fd_entry = fd_table.get_entry(tr, tint64);
m_fd_name_value.read_value(tr, fd_entry, tstr);
break;
}
case PPME_SYSCALL_OPEN_BY_HANDLE_AT_X:
{
m_lastevent_fd_field.read_value(tr, thread_entry, tint64);
auto fd_entry = fd_table.get_entry(tr, tint64);
m_fd_name_value.read_value(tr, fd_entry, tstr);
break;
}
default:
break;
}
break;
}
case plugin_sinsp_filterchecks::TYPE_FDNAMERAW:
{
m_lastevent_fd_field.read_value(tr, thread_entry, tint64);
auto fd_entry = fd_table.get_entry(tr, tint64);
m_fd_nameraw_value.read_value(tr, fd_entry, tstr);
break;
break;
}
case plugin_sinsp_filterchecks::TYPE_INO:
{
break;
}
default:
break;
}
Expand All @@ -692,29 +776,118 @@ bool anomalydetection::extract_filterchecks_concat_profile(int64_t thread_id, co
return true;
}

// Adopted from the k8smeta plugin, obtain a param from a sinsp event
static inline sinsp_param get_syscall_evt_param(void* evt, uint32_t num_param)
{
uint32_t dataoffset = 0;
// pointer to the lengths array inside the event.
auto len = (uint16_t*)((uint8_t*)evt +
sizeof(falcosecurity::_internal::ss_plugin_event));
for(uint32_t j = 0; j < num_param; j++)
{
// sum lengths of the previous params.
dataoffset += len[j];
}
return {.param_len = len[num_param],
.param_pointer =
((uint8_t*)&len
[((falcosecurity::_internal::ss_plugin_event*)evt)
->nparams]) +
dataoffset};
}

bool anomalydetection::parse_event(const falcosecurity::parse_event_input& in)
{
auto& evt = in.get_event_reader();
auto& tr = in.get_table_reader();
auto& tw = in.get_table_writer();
int64_t thread_id = evt.get_tid();

// note: Plugin event parsing guaranteed to happen after libs' `sinsp_parser::process_event` has finished.
// Needs to stay in sync w/ libs updates.
// Ultimately gated by `base_syscalls` restrictions if Falco is used w/ `base_syscalls`.


// The plugin currently cannot access for examle m_lastevent_fd from libs
// Write this info to tinfo within the plugin
switch(evt.get_type())
{
case PPME_SYSCALL_OPEN_X: // fd param 0
case PPME_SOCKET_ACCEPT_5_X:
case PPME_SOCKET_ACCEPT4_6_X:
case PPME_SYSCALL_CREAT_X:
{
auto res_param = get_syscall_evt_param(in.get_event_reader().get_buf(),
0);
if (res_param.param_pointer == nullptr)
{
return false;
}

int64_t fd = *(int64_t*)(res_param.param_pointer);
auto thread_entry = m_thread_table.get_entry(tr, thread_id);
m_lastevent_fd_field.write_value(tw, thread_entry, fd);
break;
}
case PPME_SOCKET_CONNECT_X: // fd param 2
{
auto res_param = get_syscall_evt_param(in.get_event_reader().get_buf(),
2);
if (res_param.param_pointer == nullptr)
{
return false;
}
int64_t fd = *(int64_t*)(res_param.param_pointer);
auto thread_entry = m_thread_table.get_entry(tr, thread_id);
m_lastevent_fd_field.write_value(tw, thread_entry, fd);
break;
}
case PPME_SYSCALL_OPENAT_2_X: // fd param 0
case PPME_SYSCALL_OPENAT2_X:
{
auto res_param = get_syscall_evt_param(in.get_event_reader().get_buf(),
0);
if (res_param.param_pointer == nullptr)
{
return false;
}
int64_t fd = *(int64_t*)(res_param.param_pointer);
auto thread_entry = m_thread_table.get_entry(tr, thread_id);
m_lastevent_fd_field.write_value(tw, thread_entry, fd);
break;
}
case PPME_SYSCALL_OPEN_BY_HANDLE_AT_X:
{
auto res_param = get_syscall_evt_param(in.get_event_reader().get_buf(),
0);
if (res_param.param_pointer == nullptr)
{
return false;
}
int64_t fd = *(int64_t*)(res_param.param_pointer);
auto thread_entry = m_thread_table.get_entry(tr, thread_id);
m_lastevent_fd_field.write_value(tw, thread_entry, fd);
break;
}
default:
break;
}

// Loop over behavior profiles, extract profile fields and update the count_min_sketch counts.
int i = 0;
std::string behavior_profile_concat_str;
for(const auto& set : m_behavior_profiles_event_codes)
{
if(set.find((ppm_event_code)evt.get_type()) != set.end())
{
int64_t thread_id = in.get_event_reader().get_tid();
if(thread_id <= 0)
{
return false;
}
try
{
behavior_profile_concat_str.clear();
if (i < m_n_sketches && extract_filterchecks_concat_profile(thread_id, tr, m_behavior_profiles_fields[i], behavior_profile_concat_str) && !behavior_profile_concat_str.empty())
if (i < m_n_sketches && extract_filterchecks_concat_profile(evt, tr, m_behavior_profiles_fields[i], behavior_profile_concat_str) && !behavior_profile_concat_str.empty())
{
m_count_min_sketches[i].get()->update(behavior_profile_concat_str, (uint64_t)1);
}
Expand Down
47 changes: 37 additions & 10 deletions plugins/anomalydetection/src/plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,13 @@ limitations under the License.
#include <unordered_set>
#include <sstream>

# define UINT32_MAX (4294967295U)
#define UINT32_MAX (4294967295U)

struct sinsp_param
{
uint16_t param_len;
uint8_t* param_pointer;
};

class anomalydetection
{
Expand Down Expand Up @@ -118,7 +124,7 @@ class anomalydetection
bool parse_event(const falcosecurity::parse_event_input& in);

// Custom helper function within event parsing
bool extract_filterchecks_concat_profile(int64_t thread_id, const falcosecurity::table_reader &tr, const std::vector<plugin_sinsp_filterchecks_field>& fields, std::string& behavior_profile_concat_str);
bool extract_filterchecks_concat_profile(const falcosecurity::event_reader &evt, const falcosecurity::table_reader &tr, const std::vector<plugin_sinsp_filterchecks_field>& fields, std::string& behavior_profile_concat_str);

private:

Expand All @@ -138,6 +144,8 @@ class anomalydetection
falcosecurity::table m_thread_table;
// Accessors to the fixed fields of falcosecurity/libs' thread table -> non comprehensive re-definition of sinsp_threadinfo
// Reference in falcosecurity/libs: userspace/libsinsp/threadinfo.h

/* proc related*/
falcosecurity::table_field m_tid; ///< The id of this thread
falcosecurity::table_field m_pid; ///< The id of the process containing this thread. In single thread threads, this is equal to tid.
falcosecurity::table_field m_ptid; ///< The id of the process that started this thread.
Expand All @@ -148,20 +156,39 @@ class anomalydetection
falcosecurity::table_field m_exe_writable;
falcosecurity::table_field m_exe_upper_layer; ///< True if the executable file belongs to upper layer in overlayfs
falcosecurity::table_field m_exe_from_memfd; ///< True if the executable is stored in fileless memory referenced by memfd
falcosecurity::table_field m_args; ///< Command line arguments (e.g. "-d1")
falcosecurity::table_field m_args_value; ///< String value entry from the args array
falcosecurity::table_field m_env; ///< Environment variables
falcosecurity::table_field m_container_id; ///< heuristic-based container id
falcosecurity::table_field m_uid; ///< user uid
falcosecurity::table_field m_user; ///< user infos
falcosecurity::table_field m_loginuid; ///< auid
falcosecurity::table_field m_loginuser; ///< loginuser infos (auid)
falcosecurity::table_field m_args; ///< args subtable
falcosecurity::table_field m_args_value; ///< Value entry to command line arguments (e.g. "-d1") from the args array
falcosecurity::table_field m_env; ///< Environment variables subtable
falcosecurity::table_field m_env_value; ///< Value entry
falcosecurity::table_field m_group; ///< group infos
falcosecurity::table_field m_vtid; ///< The virtual id of this thread.
falcosecurity::table_field m_vpid; ///< The virtual id of the process containing this thread. In single thread threads, this is equal to vtid.
falcosecurity::table_field m_vpgid; // The virtual process group id, as seen from its pid namespace
falcosecurity::table_field m_tty; ///< Number of controlling terminal
falcosecurity::table_field m_cwd; ///< current working directory

/* user related */
// Not available until the next libs plugins API expansion
falcosecurity::table_field m_uid; ///< user uid
falcosecurity::table_field m_user; ///< user infos
falcosecurity::table_field m_loginuid; ///< auid
falcosecurity::table_field m_loginuser; ///< loginuser infos (auid)

/* fd or fs related */
falcosecurity::table_field m_fds; ///< fd subtable
falcosecurity::table_field m_fd_name_value;
falcosecurity::table_field m_fd_nameraw_value;
falcosecurity::table_field m_fd_ino_value;
falcosecurity::table_field m_fd_type_value;
falcosecurity::table_field m_fd_flags_value;
falcosecurity::table_field m_fd_dev_value;
falcosecurity::table_field m_fd_mount_id_value;

/* container related */
falcosecurity::table_field m_container_id; ///< heuristic-based container id

/* Custom fields*/
falcosecurity::table_field m_lastevent_fd_field;
};

// required; standard plugin API
Expand Down
2 changes: 1 addition & 1 deletion plugins/anomalydetection/test/include/test_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

#define INIT_CONFIG "{\"count_min_sketch\":{\"enabled\":true,\"n_sketches\":3,\"gamma_eps\":[[0.001,0.0001],[0.001,0.0001],[0.001,0.0001]],\"behavior_profiles\":[{\"fields\":\"%container.id %proc.name %proc.pname %proc.exepath %proc.pexepath %proc.tty %proc.vpid %proc.pvid]\",\"event_codes\":[293,331]},{\"fields\":\"%container.id %proc.name %proc.aname[1] %proc.aname[2] %proc.aname[3] %proc.exepath %proc.tty %proc.vpgid.name %proc.sname %fd.name\",\"event_codes\":[3,307,327]},{\"fields\":\"%container.id %proc.cmdline %proc.name %proc.aname[0] %proc.aname[1] %proc.aname[2] %proc.aname[3] %proc.aname[4] %proc.aname[5] %proc.aname[6] %proc.aname[7] %proc.pid %proc.apid[0] %proc.apid[1] %proc.apid[2] %proc.apid[3] %proc.apid[4] %proc.apid[5] %proc.apid[6] %proc.apid[7] %proc.exepath %proc.aexepath[0] %proc.aexepath[1] %proc.aexepath[2] %proc.aexepath[3] %proc.aexepath[4] %proc.aexepath[5] %proc.aexepath[6] %proc.aexepath[7] %proc.vpgid %proc.vpgid.name %proc.sid %proc.sname\",\"event_codes\":[293,331]}]}}"
#define INIT_CONFIG "{\"count_min_sketch\":{\"enabled\":true,\"n_sketches\":3,\"gamma_eps\":[[0.001,0.0001],[0.001,0.0001],[0.001,0.0001]],\"behavior_profiles\":[{\"fields\":\"%container.id %proc.name %proc.pname %proc.exepath %proc.pexepath %proc.tty %proc.vpid %proc.pvid]\",\"event_codes\":[293,331]},{\"fields\":\"%fd.ino %fd.nameraw %fd.name\",\"event_codes\":[3,307,327]},{\"fields\":\"%container.id %proc.cmdline %proc.name %proc.aname[0] %proc.aname[1] %proc.aname[2] %proc.aname[3] %proc.aname[4] %proc.aname[5] %proc.aname[6] %proc.aname[7] %proc.pid %proc.apid[0] %proc.apid[1] %proc.apid[2] %proc.apid[3] %proc.apid[4] %proc.apid[5] %proc.apid[6] %proc.apid[7] %proc.exepath %proc.aexepath[0] %proc.aexepath[1] %proc.aexepath[2] %proc.aexepath[3] %proc.aexepath[4] %proc.aexepath[5] %proc.aexepath[6] %proc.aexepath[7] %proc.vpgid %proc.vpgid.name %proc.sid %proc.sname\",\"event_codes\":[293,331]}]}}"

#define ASSERT_PLUGIN_INITIALIZATION(p_o, p_l) \
{ \
Expand Down
Loading

0 comments on commit 6d18a5b

Please sign in to comment.