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 21, 2022
1 parent 550144c commit 8ced729
Show file tree
Hide file tree
Showing 3 changed files with 202 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
259 changes: 163 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,42 @@ bool sinsp_usergroup_manager::clear_host_users_groups()
return res;
}

scap_userinfo *sinsp_usergroup_manager::userinfo_map_insert(
userinfo_map &map,
uint32_t uid,
uint32_t gid,
const char *name,
const char *home,
const char *shell)
{
ASSERT(name);
ASSERT(home);
ASSERT(shell);

auto &usr = map[uid];
usr.uid = uid;
usr.gid = gid;
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_groupinfo *sinsp_usergroup_manager::groupinfo_map_insert(
groupinfo_map &map,
uint32_t gid,
const char *name)
{
ASSERT(name);

auto &grp = map[gid];
grp.gid = gid;
strlcpy(grp.name, name, MAX_CREDENTIALS_STR_LEN);

return &grp;
}

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 @@ -249,59 +281,98 @@ scap_userinfo *sinsp_usergroup_manager::add_user(const string &container_id, uin
scap_userinfo *usr = get_user(container_id, uid);
if (!usr)
{
#ifdef HAVE_PWD_H
struct passwd *p = nullptr;
if (container_id.empty() && !name)
bool do_notify{false};
if (name)
{
usr = userinfo_map_insert(
m_userlist[container_id],
uid,
gid,
name,
home,
shell);
do_notify = true;
}
else if (container_id.empty())
{
#ifdef HAVE_PWD_H
// On Host, try to load info from db
p = __getpwuid(uid);
auto* 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->pw_uid,
p->pw_gid,
p->pw_name,
p->pw_dir,
p->pw_shell);
do_notify = true;
}
}
#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)
if (notify && do_notify)
{
notify_user_changed(&userlist[uid], container_id);
notify_user_changed(usr, 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->pw_uid,
p->pw_gid,
p->pw_name,
p->pw_dir,
p->pw_shell);

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 @@ -334,35 +405,31 @@ scap_groupinfo *sinsp_usergroup_manager::add_group(const string &container_id, u
scap_groupinfo *gr = get_group(container_id, gid);
if (!gr)
{
#ifdef HAVE_GRP_H
struct group *p = nullptr;
if (container_id.empty() && !name)
bool do_notify{false};
if (name)
{
gr = groupinfo_map_insert(m_grouplist[container_id], gid, name);
do_notify = true;
}
else if (container_id.empty())
{
#ifdef HAVE_GRP_H
// On Host, try to load info from db
p = __getgrgid(gid);
if (p)
auto* g = __getgrgid(gid);
if (g)
{
name = p->gr_name;
gr = groupinfo_map_insert(m_grouplist[container_id], g->gr_gid, g->gr_name);
do_notify = 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)
if (notify && do_notify)
{
notify_group_changed(&grplist[gid], container_id, true);
notify_group_changed(gr, 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 +438,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->gr_gid, g->gr_name);

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 +726,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
}
Loading

0 comments on commit 8ced729

Please sign in to comment.