Skip to content

Commit

Permalink
Addl docker container info (#655)
Browse files Browse the repository at this point in the history
* Whitespace changes.

Checking in separate from other changes.

* Change glob matching to allow path separators.

Change glob matching to allow *, ? to match the path separator
/. This allows for matching /proc/* as anything starting with /proc
instead of having to match all path components.

* Add ability to detect/show privileged status.

In sinsp_container_manager::parse_docker(), parse the Privileged field
out of the json output and use it to set the instance variable
m_privileged.

Modify container_to_json/parse_container_json_evt to dump/read the
privileged status from .scap files.

New filtercheck container.privileged returns the privileged status
as a boolean.

Although other container types support the notion of privileged, I only
support this filtercheck for docker containers. For non-docker
containers, container.privileged returns NULL.

Write privileged to/from scap files.

* Add ability to display container mount info.

In sinsp_container_manager::parse_docker(), parse the Mounts field into
a vector of class container_mount_info objects.

Modify container_to_json/parse_container_json_evt to dump/read the
mount information from .scap files.

New filtercheck container.mounts displays the mount information as a
comma-separated list of mount tuples
<source>:<dest>:<mode>:<rdwr>:<propagation>, for example:

mounts=/tmp:/foo/tmp::true::,/var/lib/docker/volumes/51c63c9efcd052551dd4898736dffb2692acbf6afd8d3f4d2f0cb89a7f8ace4a/_data:/data::true:rprivate:

Note how empty values for mode/propagation turn into empty strings.

This output is pretty awkward and verbose, so there are additional
filterchecks that allow you to select any given attribute from a
single mount. New filterchecks
container.mount.{source,dest,dest,mode,rdwr,propagation} allow selecting
any of the mount information indexed either by mount id
"container.mount.mode[0]" or mount source
"container.mount.mode[/var/log]". container.mount.source is different in
that it's indexed by the mount destination instead of the mount source.

When selecting a mount by source/dest pathname, you can provide a glob
match instead (e.g. container.mount.mode[/var/log/*]). In this case, the
first matching mount is returned.

You can also use this indexing to return all the mount information for a
single mount. New filtercheck container.mount returns the tuple
information for a single mount, indexed by number (container.mount[0])
or source path/glob (container.mount[/var/log]. This can also be used to
test if a mount exists, like container.mount[/proc/*] to detect
containers that mount /proc or other sensitive directories.

Write mounts to/from .scap files.
  • Loading branch information
mstemm authored and Luca Marturana committed Oct 10, 2016
1 parent 289324d commit 65900c5
Show file tree
Hide file tree
Showing 6 changed files with 431 additions and 6 deletions.
85 changes: 82 additions & 3 deletions userspace/libsinsp/container.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,59 @@ along with sysdig. If not, see <http://www.gnu.org/licenses/>.
#include "sinsp.h"
#include "sinsp_int.h"
#include "container.h"
#include "utils.h"

void sinsp_container_info::parse_json_mounts(const Json::Value &mnt_obj, vector<sinsp_container_info::container_mount_info> &mounts)
{
if(!mnt_obj.isNull() && mnt_obj.isArray())
{
for(uint32_t i=0; i<mnt_obj.size(); i++)
{
const Json::Value &mount = mnt_obj[i];
mounts.emplace_back(mount["Source"], mount["Destination"],
mount["Mode"], mount["RW"],
mount["Propagation"]);
}
}
}

sinsp_container_info::container_mount_info *sinsp_container_info::mount_by_idx(uint32_t idx)
{
if (idx >= m_mounts.size())
{
return NULL;
}

return &(m_mounts[idx]);
}

sinsp_container_info::container_mount_info *sinsp_container_info::mount_by_source(std::string &source)
{
// note: linear search
for (auto &mntinfo :m_mounts)
{
if(sinsp_utils::glob_match(source.c_str(), mntinfo.m_source.c_str()))
{
return &mntinfo;
}
}

return NULL;
}

sinsp_container_info::container_mount_info *sinsp_container_info::mount_by_dest(std::string &dest)
{
// note: linear search
for (auto &mntinfo :m_mounts)
{
if(sinsp_utils::glob_match(dest.c_str(), mntinfo.m_dest.c_str()))
{
return &mntinfo;
}
}

return NULL;
}

sinsp_container_manager::sinsp_container_manager(sinsp* inspector) :
m_inspector(inspector),
Expand All @@ -41,7 +94,7 @@ bool sinsp_container_manager::remove_inactive_containers()
m_last_flush_time_ns = m_inspector->m_lastevent_ts - m_inspector->m_inactive_container_scan_time_ns + 30 * ONE_SECOND_IN_NS;
}

if(m_inspector->m_lastevent_ts >
if(m_inspector->m_lastevent_ts >
m_last_flush_time_ns + m_inspector->m_inactive_thread_scan_time_ns)
{
res = true;
Expand Down Expand Up @@ -187,7 +240,7 @@ bool sinsp_container_manager::resolve_container(sinsp_threadinfo* tinfo, bool qu
if(pos != string::npos)
{
if(cgroup.length() - pos - 1 == 64 &&
cgroup.find_first_not_of("0123456789abcdefABCDEF", pos + 1) == string::npos)
cgroup.find_first_not_of("0123456789abcdefABCDEF", pos + 1) == string::npos)
{
container_info.m_type = CT_DOCKER;
container_info.m_id = cgroup.substr(pos + 1, 12);
Expand Down Expand Up @@ -407,6 +460,24 @@ string sinsp_container_manager::container_to_json(const sinsp_container_info& co
container["type"] = container_info.m_type;
container["name"] = container_info.m_name;
container["image"] = container_info.m_image;
container["privileged"] = container_info.m_privileged;

Json::Value mounts = Json::arrayValue;

for (auto &mntinfo : container_info.m_mounts)
{
Json::Value mount;

mount["Source"] = mntinfo.m_source;
mount["Destination"] = mntinfo.m_dest;
mount["Mode"] = mntinfo.m_mode;
mount["RW"] = mntinfo.m_rdwr;
mount["Propagation"] = mntinfo.m_propagation;

mounts.append(mount);
}

container["Mounts"] = mounts;

char addrbuff[100];
uint32_t iph = ntohl(container_info.m_container_ip);
Expand Down Expand Up @@ -552,7 +623,7 @@ bool sinsp_container_manager::parse_docker(sinsp_container_info* container)
if(v.isArray())
{
for(uint32_t j = 0; j < v.size(); ++j)
{
{
sinsp_container_info::container_port_mapping port_mapping;

ip = v[j]["HostIp"].asString();
Expand Down Expand Up @@ -609,6 +680,14 @@ bool sinsp_container_manager::parse_docker(sinsp_container_info* container)
{
container->m_cpu_period = cpu_period;
}
const Json::Value &privileged = host_config_obj["Privileged"];
if(!privileged.isNull() && privileged.isBool())
{
container->m_privileged = privileged.asBool();
}

sinsp_container_info::parse_json_mounts(root["Mounts"], container->m_mounts);

return true;
}

Expand Down
59 changes: 59 additions & 0 deletions userspace/libsinsp/container.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,57 @@ class sinsp_container_info
uint16_t m_container_port;
};

class container_mount_info
{
public:
container_mount_info():
m_source(""),
m_dest(""),
m_mode(""),
m_rdwr(false),
m_propagation("")
{
}

container_mount_info(const Json::Value &source, const Json::Value &dest,
const Json::Value &mode, const Json::Value &rw,
const Json::Value &propagation)
{
get_string_value(source, m_source);
get_string_value(dest, m_dest);
get_string_value(mode, m_mode);
get_string_value(propagation, m_propagation);

if(!rw.isNull() && rw.isBool())
{
m_rdwr = rw.asBool();
}
}

std::string to_string()
{
return m_source + ":" +
m_dest + ":" +
m_mode + ":" +
(m_rdwr ? "true" : "false") + ":" +
m_propagation;
}

inline void get_string_value(const Json::Value &val, std::string &result)
{
if(!val.isNull() && val.isString())
{
result = val.asString();
}
}

std::string m_source;
std::string m_dest;
std::string m_mode;
bool m_rdwr;
std::string m_propagation;
};

sinsp_container_info():
m_container_ip(0),
m_memory_limit(0),
Expand All @@ -55,11 +106,19 @@ class sinsp_container_info
{
}

static void parse_json_mounts(const Json::Value &mnt_obj, vector<container_mount_info> &mounts);

container_mount_info *mount_by_idx(uint32_t idx);
container_mount_info *mount_by_source(std::string &source);
container_mount_info *mount_by_dest(std::string &dest);

string m_id;
sinsp_container_type m_type;
string m_name;
string m_image;
uint32_t m_container_ip;
bool m_privileged;
vector<container_mount_info> m_mounts;
vector<container_port_mapping> m_port_mappings;
map<string, string> m_labels;
string m_mesos_task_id;
Expand Down
Loading

0 comments on commit 65900c5

Please sign in to comment.