From ae12bb3fe7d6e1d0fd3fe27e5446610a5e0db291 Mon Sep 17 00:00:00 2001 From: Amir Rossert Date: Wed, 8 Aug 2018 09:46:21 +0300 Subject: [PATCH] Added loginuid (auid) argument to execve exit events. * Added data member to threadinfo struct `m_loginuid` * Extract the value from kernel module & eBPF (still need to implement user namespace support) * Extract the loginuid value from "/proc//loginuid" on startup * Added filters for "user.loginuid" & "user.loginname" * Save/load from scap file sysdig-CLA-1.0-signed-off-by: Amir Rossert --- driver/bpf/fillers.h | 11 +++++++++ driver/event_table.c | 2 +- driver/ppm_fillers.c | 15 +++++++++++++ userspace/libscap/scap.h | 1 + userspace/libscap/scap_procs.c | 35 +++++++++++++++++++++++++++++ userspace/libscap/scap_savefile.c | 18 +++++++++++++-- userspace/libsinsp/filterchecks.cpp | 31 ++++++++++++------------- userspace/libsinsp/filterchecks.h | 2 ++ userspace/libsinsp/parsers.cpp | 11 +++++++++ userspace/libsinsp/sinsp.cpp | 18 +++++++++++++++ userspace/libsinsp/sinsp.h | 12 ++++++++++ userspace/libsinsp/threadinfo.cpp | 2 ++ userspace/libsinsp/threadinfo.h | 1 + 13 files changed, 141 insertions(+), 18 deletions(-) diff --git a/driver/bpf/fillers.h b/driver/bpf/fillers.h index 9ce07a58ef..a436913657 100644 --- a/driver/bpf/fillers.h +++ b/driver/bpf/fillers.h @@ -1567,6 +1567,7 @@ FILLER(proc_startupdate_3, true) kgid_t egid; pid_t vtid; pid_t vpid; + kuid_t loginuid; /* * flags @@ -1688,6 +1689,16 @@ FILLER(proc_startupdate_3, true) * pgid */ res = bpf_val_to_ring_type(data, bpf_task_pgrp_vnr(task), PT_PID); + if (res != PPM_SUCCESS) + return res; + + /* + * loginuid + */ + /* TODO: implement user namespace support */ + res = bpf_val_to_ring_type(data, task->loginuid.val, PT_INT32); + if (res != PPM_SUCCESS) + return res; } return res; diff --git a/driver/event_table.c b/driver/event_table.c index 2e30e885b7..39b401c5e4 100644 --- a/driver/event_table.c +++ b/driver/event_table.c @@ -314,7 +314,7 @@ const struct ppm_event_info g_event_info[PPM_EVENT_MAX] = { /* PPME_PAGE_FAULT_E */ {"page_fault", EC_OTHER, EF_SKIPPARSERESET | EF_DROP_FALCO, 3, {{"addr", PT_UINT64, PF_HEX}, {"ip", PT_UINT64, PF_HEX}, {"error", PT_FLAGS32, PF_HEX, pf_flags} } }, /* PPME_PAGE_FAULT_X */ {"NA5", EC_OTHER, EF_UNUSED, 0}, /* PPME_SYSCALL_EXECVE_19_E */{"execve", EC_PROCESS, EF_MODIFIES_STATE, 1, {{"filename", PT_FSPATH, PF_NA} } }, - /* PPME_SYSCALL_EXECVE_19_X */{"execve", EC_PROCESS, EF_MODIFIES_STATE, 18, {{"res", PT_ERRNO, PF_DEC}, {"exe", PT_CHARBUF, PF_NA}, {"args", PT_BYTEBUF, PF_NA}, {"tid", PT_PID, PF_DEC}, {"pid", PT_PID, PF_DEC}, {"ptid", PT_PID, PF_DEC}, {"cwd", PT_CHARBUF, PF_NA}, {"fdlimit", PT_UINT64, PF_DEC}, {"pgft_maj", PT_UINT64, PF_DEC}, {"pgft_min", PT_UINT64, PF_DEC}, {"vm_size", PT_UINT32, PF_DEC}, {"vm_rss", PT_UINT32, PF_DEC}, {"vm_swap", PT_UINT32, PF_DEC}, {"comm", PT_CHARBUF, PF_NA}, {"cgroups", PT_BYTEBUF, PF_NA}, {"env", PT_BYTEBUF, PF_NA}, {"tty", PT_INT32, PF_DEC}, {"pgid", PT_PID, PF_DEC} } }, + /* PPME_SYSCALL_EXECVE_19_X */{"execve", EC_PROCESS, EF_MODIFIES_STATE, 19, {{"res", PT_ERRNO, PF_DEC}, {"exe", PT_CHARBUF, PF_NA}, {"args", PT_BYTEBUF, PF_NA}, {"tid", PT_PID, PF_DEC}, {"pid", PT_PID, PF_DEC}, {"ptid", PT_PID, PF_DEC}, {"cwd", PT_CHARBUF, PF_NA}, {"fdlimit", PT_UINT64, PF_DEC}, {"pgft_maj", PT_UINT64, PF_DEC}, {"pgft_min", PT_UINT64, PF_DEC}, {"vm_size", PT_UINT32, PF_DEC}, {"vm_rss", PT_UINT32, PF_DEC}, {"vm_swap", PT_UINT32, PF_DEC}, {"comm", PT_CHARBUF, PF_NA}, {"cgroups", PT_BYTEBUF, PF_NA}, {"env", PT_BYTEBUF, PF_NA}, {"tty", PT_INT32, PF_DEC}, {"pgid", PT_PID, PF_DEC}, {"loginuid", PT_INT32, PF_DEC} } }, /* PPME_SYSCALL_SETPGID_E */{"setpgid", EC_PROCESS, EF_MODIFIES_STATE, 2, {{"pid", PT_PID, PF_DEC}, {"pgid", PT_PID, PF_DEC} } }, /* PPME_SYSCALL_SETPGID_X */{"setpgid", EC_PROCESS, EF_MODIFIES_STATE, 1, {{"res", PT_PID, PF_DEC} } }, /* PPME_SYSCALL_BPF_E */{"bpf", EC_OTHER, EF_CREATES_FD, 1, {{"cmd", PT_INT64, PF_DEC} } }, diff --git a/driver/ppm_fillers.c b/driver/ppm_fillers.c index e595c0f049..e3c3662a2b 100644 --- a/driver/ppm_fillers.c +++ b/driver/ppm_fillers.c @@ -36,6 +36,7 @@ along with sysdig. If not, see . #include #include #include +#include #ifdef CONFIG_CGROUPS #include #endif @@ -990,6 +991,20 @@ int f_proc_startupdate(struct event_filler_arguments *args) #endif if (unlikely(res != PPM_SUCCESS)) return res; + + /* + * loginuid + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) + val = from_kuid(current_user_ns(), audit_get_loginuid(current)); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) + val = audit_get_loginuid(current); +#else + val = audit_get_loginuid(current->audit_context); +#endif + res = val_to_ring(args, val, 0, false, 0); + if (unlikely(res != PPM_SUCCESS)) + return res; } return add_sentinel(args); diff --git a/userspace/libscap/scap.h b/userspace/libscap/scap.h index c6b3fe31c5..bb3dac1fa3 100644 --- a/userspace/libscap/scap.h +++ b/userspace/libscap/scap.h @@ -240,6 +240,7 @@ typedef struct scap_threadinfo scap_fdinfo* fdlist; ///< The fd table for this process uint64_t clone_ts; int32_t tty; + int32_t loginuid; ///< loginuid (auid) UT_hash_handle hh; ///< makes this structure hashable }scap_threadinfo; diff --git a/userspace/libscap/scap_procs.c b/userspace/libscap/scap_procs.c index e2062c933a..44e67e4c15 100644 --- a/userspace/libscap/scap_procs.c +++ b/userspace/libscap/scap_procs.c @@ -472,6 +472,31 @@ int32_t scap_proc_fill_root(struct scap_threadinfo* tinfo, const char* procdirna } } +int32_t scap_proc_fill_loginuid(struct scap_threadinfo* tinfo, const char* procdirname) +{ + uint32_t loginuid; + char loginuid_path[SCAP_MAX_PATH_SIZE]; + char line[512]; + snprintf(loginuid_path, sizeof(loginuid_path), "%sloginuid", procdirname); + FILE* f = fopen(loginuid_path, "r"); + if(f == NULL) + { + ASSERT(false); + return SCAP_FAILURE; + } + fgets(line, sizeof(line), f); + if(sscanf(line, "%" PRId32, &loginuid) == 1) + { + tinfo->loginuid = loginuid; + return SCAP_SUCCESS; + } + else + { + ASSERT(false); + return SCAP_FAILURE; + } +} + // // Add a process to the list by parsing its entry under /proc // @@ -747,6 +772,16 @@ static int32_t scap_proc_add_from_proc(scap_t* handle, uint32_t tid, int parentt return SCAP_FAILURE; } + // + // set the loginuid + // + if(SCAP_FAILURE == scap_proc_fill_loginuid(tinfo, dir_name)) + { + snprintf(error, SCAP_LASTERR_SIZE, "can't fill loginuid for %s", dir_name); + free(tinfo); + return SCAP_FAILURE; + } + if(stat(dir_name, &dirstat) == 0) { tinfo->clone_ts = dirstat.st_ctim.tv_sec*1000000000 + dirstat.st_ctim.tv_nsec; diff --git a/userspace/libscap/scap_savefile.c b/userspace/libscap/scap_savefile.c index 0ab7b971ff..db799b0a93 100755 --- a/userspace/libscap/scap_savefile.c +++ b/userspace/libscap/scap_savefile.c @@ -398,7 +398,8 @@ int32_t scap_write_proclist_entry_bufs(scap_t *handle, scap_dumper_t *d, struct scap_dump_write(d, &(cgroupslen), sizeof(uint16_t)) != sizeof(uint16_t) || scap_dump_writev(d, cgroups, cgroupscnt) != cgroupslen || scap_dump_write(d, &rootlen, sizeof(uint16_t)) != sizeof(uint16_t) || - scap_dump_write(d, (char *) root, rootlen) != rootlen) + scap_dump_write(d, (char *) root, rootlen) != rootlen || + scap_dump_write(d, &(tinfo->loginuid), sizeof(uint32_t)) != sizeof(uint32_t)) { snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "error writing to file (2)"); return SCAP_FAILURE; @@ -459,7 +460,8 @@ static int32_t scap_write_proclist(scap_t *handle, scap_dumper_t *d) sizeof(int64_t) + // vtid sizeof(int64_t) + // vpid 2 + tinfo->cgroups_len + - 2 + strnlen(tinfo->root, SCAP_MAX_PATH_SIZE)); + 2 + strnlen(tinfo->root, SCAP_MAX_PATH_SIZE) + + sizeof(int32_t)); // loginuid; lengths[idx++] = il; totlen += il; @@ -1217,6 +1219,7 @@ static int32_t scap_read_proclist(scap_t *handle, gzFile f, uint32_t block_lengt tinfo.clone_ts = 0; tinfo.tty = 0; tinfo.exepath[0] = 0; + tinfo.loginuid = -1; // // len @@ -1665,6 +1668,17 @@ static int32_t scap_read_proclist(scap_t *handle, gzFile f, uint32_t block_lengt // ... // } + // + // loginuid + // + if(sub_len && (subreadsize + sizeof(int32_t)) <= sub_len) + { + readsize = gzread(f, &(tinfo.loginuid), sizeof(int32_t)); + CHECK_READ_SIZE(readsize, sizeof(uint32_t)); + subreadsize += readsize; + } + + // // All parsed. Add the entry to the table, or fire the notification callback // diff --git a/userspace/libsinsp/filterchecks.cpp b/userspace/libsinsp/filterchecks.cpp index 4584bae76a..f55268784d 100644 --- a/userspace/libsinsp/filterchecks.cpp +++ b/userspace/libsinsp/filterchecks.cpp @@ -4066,6 +4066,8 @@ const filtercheck_field_info sinsp_filter_check_user_fields[] = {PT_CHARBUF, EPF_NONE, PF_NA, "user.name", "user name."}, {PT_CHARBUF, EPF_NONE, PF_NA, "user.homedir", "home directory of the user."}, {PT_CHARBUF, EPF_NONE, PF_NA, "user.shell", "user's shell."}, + {PT_INT32, EPF_NONE, PF_ID, "user.loginuid", "audit user id (auid)."}, + {PT_CHARBUF, EPF_NONE, PF_NA, "user.loginname", "audit user name (auid)."}, }; sinsp_filter_check_user::sinsp_filter_check_user() @@ -4092,26 +4094,15 @@ uint8_t* sinsp_filter_check_user::extract(sinsp_evt *evt, OUT uint32_t* len, boo return NULL; } - if(m_field_id != TYPE_UID) + if(m_field_id != TYPE_UID && m_field_id != TYPE_LOGINUID && m_field_id != TYPE_LOGINNAME) { - unordered_map::const_iterator it; - ASSERT(m_inspector != NULL); - const unordered_map* userlist = m_inspector->get_userlist(); - - if(tinfo->m_uid == 0xffffffff) - { - return NULL; - } - - it = userlist->find(tinfo->m_uid); - if(it == userlist->end()) + uinfo = m_inspector->get_user(tinfo->m_uid); + ASSERT(uinfo != NULL); + if(uinfo == NULL) { return NULL; } - - uinfo = it->second; - ASSERT(uinfo != NULL); } switch(m_field_id) @@ -4124,6 +4115,16 @@ uint8_t* sinsp_filter_check_user::extract(sinsp_evt *evt, OUT uint32_t* len, boo RETURN_EXTRACT_CSTR(uinfo->homedir); case TYPE_SHELL: RETURN_EXTRACT_CSTR(uinfo->shell); + case TYPE_LOGINUID: + RETURN_EXTRACT_VAR(tinfo->m_loginuid); + case TYPE_LOGINNAME: + ASSERT(m_inspector != NULL); + uinfo = m_inspector->get_user(tinfo->m_loginuid); + if(uinfo == NULL) + { + return NULL; + } + RETURN_EXTRACT_CSTR(uinfo->name); default: ASSERT(false); break; diff --git a/userspace/libsinsp/filterchecks.h b/userspace/libsinsp/filterchecks.h index 881f9f2ddf..5ece1555c2 100644 --- a/userspace/libsinsp/filterchecks.h +++ b/userspace/libsinsp/filterchecks.h @@ -533,6 +533,8 @@ class sinsp_filter_check_user : public sinsp_filter_check TYPE_NAME = 1, TYPE_HOMEDIR = 2, TYPE_SHELL = 3, + TYPE_LOGINUID = 4, + TYPE_LOGINNAME = 5, }; sinsp_filter_check_user(); diff --git a/userspace/libsinsp/parsers.cpp b/userspace/libsinsp/parsers.cpp index cac1426394..2038f0b21a 100644 --- a/userspace/libsinsp/parsers.cpp +++ b/userspace/libsinsp/parsers.cpp @@ -1148,6 +1148,8 @@ void sinsp_parser::parse_clone_exit(sinsp_evt *evt) tinfo->m_tty = ptinfo->m_tty; + tinfo->m_loginuid = ptinfo->m_loginuid; + if(!(flags & PPM_CL_CLONE_THREAD)) { tinfo->m_env = ptinfo->m_env; @@ -1187,6 +1189,7 @@ void sinsp_parser::parse_clone_exit(sinsp_evt *evt) tinfo->m_sid = ptinfo->m_sid; tinfo->m_vpgid = ptinfo->m_vpgid; tinfo->m_tty = ptinfo->m_tty; + tinfo->m_loginuid = ptinfo->m_loginuid; if(!(flags & PPM_CL_CLONE_THREAD)) { tinfo->m_env = ptinfo->m_env; @@ -1748,6 +1751,14 @@ void sinsp_parser::parse_execve_exit(sinsp_evt *evt) // ... // } + // Get the loginuid + if(evt->get_num_params() > 17) + { + parinfo = evt->get_param(18); + ASSERT(parinfo->m_len == sizeof(uint32_t)); + evt->m_tinfo->m_loginuid = *(uint32_t *) parinfo->m_val; + } + // // execve starts with a clean fd list, so we get rid of the fd list that clone // copied from the parent diff --git a/userspace/libsinsp/sinsp.cpp b/userspace/libsinsp/sinsp.cpp index 6d36e328e4..098f847e38 100644 --- a/userspace/libsinsp/sinsp.cpp +++ b/userspace/libsinsp/sinsp.cpp @@ -1500,6 +1500,7 @@ threadinfo_map_t::ptr_t sinsp::get_thread_ref(int64_t tid, bool query_os_if_not_ newti->m_uid = 0xffffffff; newti->m_gid = 0xffffffff; newti->m_nchilds = 0; + newti->m_loginuid = 0xffffffff; } // @@ -1720,6 +1721,23 @@ const unordered_map* sinsp::get_userlist() return &m_userlist; } +scap_userinfo* sinsp::get_user(uint32_t uid) +{ + unordered_map::const_iterator it; + if(uid == 0xffffffff) + { + return NULL; + } + + it = m_userlist.find(uid); + if(it == m_userlist.end()) + { + return NULL; + } + + return it->second; +} + const unordered_map* sinsp::get_grouplist() { return &m_grouplist; diff --git a/userspace/libsinsp/sinsp.h b/userspace/libsinsp/sinsp.h index bde742c5c8..adf5cdb61a 100644 --- a/userspace/libsinsp/sinsp.h +++ b/userspace/libsinsp/sinsp.h @@ -522,6 +522,18 @@ class SINSP_PUBLIC sinsp */ const unordered_map* get_userlist(); + /*! + \brief Lookup for user in the user table. + + \return the \ref scap_userinfo object containing full user information, + if user not found, returns NULL. + + \note this call works with file captures as well, because the user + table is stored in the trace files. In that case, the returned + user list is the one of the machine where the capture happened. + */ + scap_userinfo* get_user(uint32_t uid); + /*! \brief Return the table with all the machine user groups. diff --git a/userspace/libsinsp/threadinfo.cpp b/userspace/libsinsp/threadinfo.cpp index 750860d6f0..ee31730a91 100644 --- a/userspace/libsinsp/threadinfo.cpp +++ b/userspace/libsinsp/threadinfo.cpp @@ -90,6 +90,7 @@ void sinsp_threadinfo::init() m_parent_loop_detected = false; m_tty = 0; m_blprogram = NULL; + m_loginuid = 0; } sinsp_threadinfo::~sinsp_threadinfo() @@ -420,6 +421,7 @@ void sinsp_threadinfo::init(scap_threadinfo* pi) m_vpid = pi->vpid; m_clone_ts = pi->clone_ts; m_tty = pi->tty; + m_loginuid = pi->loginuid; set_cgroups(pi->cgroups, pi->cgroups_len); m_root = pi->root; diff --git a/userspace/libsinsp/threadinfo.h b/userspace/libsinsp/threadinfo.h index ca1350d462..03932007c5 100644 --- a/userspace/libsinsp/threadinfo.h +++ b/userspace/libsinsp/threadinfo.h @@ -260,6 +260,7 @@ class SINSP_PUBLIC sinsp_threadinfo size_t m_program_hash; size_t m_program_hash_falco; int32_t m_tty; + int32_t m_loginuid; ///< loginuid (auid) // // State for multi-event processing