Skip to content

Commit

Permalink
new(userspace/libsinsp): container users and groups from process root
Browse files Browse the repository at this point in the history
Drop `load_from_container` in favor of `add_container_user` and `add_container_group`.
Those are called by `sinsp_threadinfo` `set_user` / `set_group` and load
the information from /proc/<pid>/root/etc.
For that to work, the process running sinsp has to be priviledged and in
the host pid namespace.
For more information see `man 5 proc`.

Signed-off-by: Angelo Puglisi <[email protected]>
  • Loading branch information
deepskyblue86 committed Oct 20, 2022
1 parent 9252975 commit 7b0099f
Show file tree
Hide file tree
Showing 3 changed files with 168 additions and 103 deletions.
22 changes: 18 additions & 4 deletions userspace/libsinsp/threadinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -505,8 +505,15 @@ void sinsp_threadinfo::set_user(uint32_t uid)
scap_userinfo *user = m_inspector->m_usergroup_manager.get_user(m_container_id, uid);
if (!user)
{
// this can fail if import_user is disabled
user = m_inspector->m_usergroup_manager.add_user(m_container_id, uid, m_group.gid, NULL, NULL, NULL, m_inspector->is_live());
// these can fail if import_user is disabled
if(m_container_id.empty())
{
user = m_inspector->m_usergroup_manager.add_user(m_container_id, uid, m_group.gid, NULL, NULL, NULL, m_inspector->is_live());
}
else
{
user = m_inspector->m_usergroup_manager.add_container_user(m_container_id, m_pid, uid, m_inspector->is_live());
}
}

if (user)
Expand All @@ -528,8 +535,15 @@ void sinsp_threadinfo::set_group(uint32_t gid)
scap_groupinfo *group = m_inspector->m_usergroup_manager.get_group(m_container_id, gid);
if (!group)
{
// this can fail if import_user is disabled
group = m_inspector->m_usergroup_manager.add_group(m_container_id, gid, NULL, m_inspector->is_live());
// these can fail if import_user is disabled
if(m_container_id.empty())
{
group = m_inspector->m_usergroup_manager.add_group(m_container_id, gid, NULL, m_inspector->is_live());
}
else
{
group = m_inspector->m_usergroup_manager.add_container_group(m_container_id, m_pid, gid, m_inspector->is_live());
}
}

if (group)
Expand Down
224 changes: 128 additions & 96 deletions userspace/libsinsp/user.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,6 @@ void sinsp_usergroup_manager::subscribe_container_mgr()
m_inspector->m_container_manager.subscribe_on_remove_container([&](const sinsp_container_info &cinfo) -> void {
delete_container_users_groups(cinfo);
});

m_inspector->m_container_manager.subscribe_on_new_container([&](const sinsp_container_info&cinfo, sinsp_threadinfo *tinfo) -> void {
load_from_container(cinfo.m_id, cinfo.m_overlayfs_root);
});
}
}

Expand Down Expand Up @@ -235,6 +231,37 @@ bool sinsp_usergroup_manager::clear_host_users_groups()
return res;
}

#ifdef HAVE_PWD_H
scap_userinfo *sinsp_usergroup_manager::userinfo_map_insert(sinsp_usergroup_manager::userinfo_map &map, passwd *p)
{
ASSERT(p);

auto &usr = map[p->pw_uid];

usr.uid = p->pw_uid;
usr.gid = p->pw_gid;
strlcpy(usr.name, p->pw_name, MAX_CREDENTIALS_STR_LEN);
strlcpy(usr.homedir, p->pw_dir, SCAP_MAX_PATH_SIZE);
strlcpy(usr.shell, p->pw_shell, SCAP_MAX_PATH_SIZE);

return &usr;
}
#endif

#ifdef HAVE_GRP_H
scap_groupinfo *sinsp_usergroup_manager::groupinfo_map_insert(sinsp_usergroup_manager::groupinfo_map &map, group *g)
{
ASSERT(g);

auto &grp = map[g->gr_gid];

grp.gid = g->gr_gid;
strlcpy(grp.name, g->gr_name, MAX_CREDENTIALS_STR_LEN);

return &grp;
}
#endif

scap_userinfo *sinsp_usergroup_manager::add_user(const string &container_id, uint32_t uid, uint32_t gid, const char *name, const char *home, const char *shell, bool notify)
{
g_logger.format(sinsp_logger::SEV_DEBUG,
Expand All @@ -257,51 +284,66 @@ scap_userinfo *sinsp_usergroup_manager::add_user(const string &container_id, uin
p = __getpwuid(uid);
if (p)
{
name = p->pw_name;
home = p->pw_dir;
shell = p->pw_shell;
usr = userinfo_map_insert(m_userlist[container_id], p);

if (notify)
{
notify_user_changed(usr, container_id);
}
}
}
#endif

if (name == NULL)
{
name = "<NA>";
}
if (home == NULL)
{
home = "<NA>";
}
if (shell == NULL)
{
shell = "<NA>";
}

auto &userlist = m_userlist[container_id];
userlist[uid].uid = uid;
userlist[uid].gid = gid;
strlcpy(userlist[uid].name, name, MAX_CREDENTIALS_STR_LEN);
strlcpy(userlist[uid].homedir, home, SCAP_MAX_PATH_SIZE);
strlcpy(userlist[uid].shell, shell, SCAP_MAX_PATH_SIZE);

if (notify)
{
notify_user_changed(&userlist[uid], container_id);
}

usr = &userlist[uid];
}
else if (name != NULL)
else if (name != NULL)
{
// Update user if it was already there
strlcpy(usr->name, name, MAX_CREDENTIALS_STR_LEN);
strlcpy(usr->homedir, home, SCAP_MAX_PATH_SIZE);
strlcpy(usr->shell, shell, SCAP_MAX_PATH_SIZE);

}
return usr;
}

scap_userinfo *sinsp_usergroup_manager::add_container_user(const std::string &container_id, int64_t pid, uint32_t uid, bool notify)
{
ASSERT(!container_id.empty());
if(container_id.empty())
{
return nullptr;
}

scap_userinfo *retval{nullptr};

#if defined HAVE_PWD_H && defined HAVE_FGET__ENT
std::string proc_root_etc = s_host_root + "/proc/" + std::to_string(pid) + "/root/etc/";

auto passwd_in_container = proc_root_etc + "passwd";
auto pwd_file = fopen(passwd_in_container.c_str(), "r");
if(pwd_file)
{
auto &userlist = m_userlist[container_id];
while(auto p = fgetpwent(pwd_file))
{
// Here we cache all container users
auto *usr = userinfo_map_insert(userlist, p);

if(notify)
{
notify_user_changed(usr, container_id);
}

if(uid == p->pw_uid)
{
retval = usr;
}
}
fclose(pwd_file);
}
#endif

return retval;
}

bool sinsp_usergroup_manager::rm_user(const string &container_id, uint32_t uid, bool notify)
{
g_logger.format(sinsp_logger::SEV_DEBUG,
Expand Down Expand Up @@ -335,34 +377,24 @@ scap_groupinfo *sinsp_usergroup_manager::add_group(const string &container_id, u
if (!gr)
{
#ifdef HAVE_GRP_H
struct group *p = nullptr;
struct group *g = nullptr;
if (container_id.empty() && !name)
{
// On Host, try to load info from db
p = __getgrgid(gid);
if (p)
g = __getgrgid(gid);
if (g)
{
name = p->gr_name;
gr = groupinfo_map_insert(m_grouplist[container_id], g);

if (notify)
{
notify_group_changed(gr, container_id, true);
}
}
}
#endif

if (name == NULL)
{
name = "<NA>";
}

auto &grplist = m_grouplist[container_id];
grplist[gid].gid = gid;
strlcpy(grplist[gid].name, name, MAX_CREDENTIALS_STR_LEN);

if (notify)
{
notify_group_changed(&grplist[gid], container_id, true);
}
gr = &grplist[gid];
}
else if (name != NULL)
else if (name != NULL)
{
// Update group if it was already there
strlcpy(gr->name, name, MAX_CREDENTIALS_STR_LEN);
Expand All @@ -371,6 +403,46 @@ scap_groupinfo *sinsp_usergroup_manager::add_group(const string &container_id, u
return gr;
}

scap_groupinfo *sinsp_usergroup_manager::add_container_group(const std::string &container_id, int64_t pid, uint32_t gid, bool notify)
{
ASSERT(!container_id.empty());
if(container_id.empty())
{
return nullptr;
}

scap_groupinfo *retval{nullptr};

#if defined HAVE_GRP_H && defined HAVE_FGET__ENT
std::string proc_root_etc = s_host_root + "/proc/" + std::to_string(pid) + "/root/etc/";

auto group_in_container = proc_root_etc + "group";
auto group_file = fopen(group_in_container.c_str(), "r");
if(group_file)
{
auto &grouplist = m_grouplist[container_id];
while(auto g = fgetgrent(group_file))
{
// Here we cache all container groups
auto *gr = groupinfo_map_insert(grouplist, g);

if(notify)
{
notify_group_changed(gr, container_id, true);
}

if(gid == g->gr_gid)
{
retval = gr;
}
}
fclose(group_file);
}
#endif

return retval;
}

bool sinsp_usergroup_manager::rm_group(const string &container_id, uint32_t gid, bool notify)
{
g_logger.format(sinsp_logger::SEV_DEBUG,
Expand Down Expand Up @@ -619,43 +691,3 @@ void sinsp_usergroup_manager::notify_group_changed(const scap_groupinfo *group,
m_inspector->m_pending_state_evts.push(cevt);
#endif
}

void sinsp_usergroup_manager::load_from_container(const std::string &container_id, const std::string &overlayfs_root)
{
if (!m_import_users)
{
return;
}

if (overlayfs_root.empty())
{
// Avoid loading from host
return;
}

#if defined HAVE_PWD_H && defined HAVE_FGET__ENT
auto passwd_in_container = overlayfs_root + "/etc/passwd";
auto pwd_file = fopen(passwd_in_container.c_str(), "r");
if(pwd_file)
{
while(auto p = fgetpwent(pwd_file))
{
add_user(container_id, p->pw_uid, p->pw_gid, p->pw_name, p->pw_dir, p->pw_shell, true);
}
fclose(pwd_file);
}
#endif

#if defined HAVE_GRP_H && defined HAVE_FGET__ENT
auto group_in_container = overlayfs_root + "/etc/group";
auto grp_file = fopen(group_in_container.c_str(), "r");
if(grp_file)
{
while(auto g = fgetgrent(grp_file))
{
add_group(container_id, g->gr_gid, g->gr_name, true);
}
fclose(grp_file);
}
#endif
}
25 changes: 22 additions & 3 deletions userspace/libsinsp/user.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ limitations under the License.

class sinsp;
class sinsp_evt;
#ifdef HAVE_PWD_H
struct passwd;
#endif
#ifdef HAVE_GRP_H
struct group;
#endif

/*
* Basic idea:
Expand Down Expand Up @@ -116,10 +122,13 @@ class sinsp_usergroup_manager

scap_userinfo *add_user(const std::string &container_id, uint32_t uid, uint32_t gid, const char *name, const char *home, const char *shell, bool notify = false);
scap_groupinfo *add_group(const std::string &container_id, uint32_t gid, const char *name, bool notify = false);

scap_userinfo *add_container_user(const std::string &container_id, int64_t pid, uint32_t uid, bool notify = false);
scap_groupinfo *add_container_group(const std::string &container_id, int64_t pid, uint32_t gid, bool notify = false);

bool rm_user(const std::string &container_id, uint32_t uid, bool notify = false);
bool rm_group(const std::string &container_id, uint32_t gid, bool notify = false);

void load_from_container(const std::string &container_id, const std::string &overlayfs_root);
bool clear_host_users_groups();

//
Expand All @@ -140,8 +149,18 @@ class sinsp_usergroup_manager
void notify_user_changed(const scap_userinfo *user, const std::string &container_id, bool added = true);
void notify_group_changed(const scap_groupinfo *group, const std::string &container_id, bool added = true);

std::unordered_map<std::string, std::unordered_map<uint32_t, scap_userinfo>> m_userlist;
std::unordered_map<std::string, std::unordered_map<uint32_t, scap_groupinfo>> m_grouplist;
using userinfo_map = std::unordered_map<uint32_t, scap_userinfo>;
using groupinfo_map = std::unordered_map<uint32_t, scap_groupinfo>;

#ifdef HAVE_PWD_H
scap_userinfo *userinfo_map_insert(userinfo_map &map, passwd *p);
#endif
#ifdef HAVE_GRP_H
scap_groupinfo *groupinfo_map_insert(groupinfo_map &map, group *g);
#endif

std::unordered_map<std::string, userinfo_map> m_userlist;
std::unordered_map<std::string, groupinfo_map> m_grouplist;
uint64_t m_last_flush_time_ns;
sinsp *m_inspector;
};
Expand Down

0 comments on commit 7b0099f

Please sign in to comment.