Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new: add container.host_pid container.host_network and container.host_ipc fields #2047

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions userspace/libsinsp/container.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,9 @@ std::string sinsp_container_manager::container_to_json(const sinsp_container_inf
container["imagetag"] = container_info.m_imagetag;
container["imagedigest"] = container_info.m_imagedigest;
container["privileged"] = container_info.m_privileged;
container["host_pid"] = container_info.m_host_pid;
container["host_network"] = container_info.m_host_network;
container["host_ipc"] = container_info.m_host_ipc;
container["is_pod_sandbox"] = container_info.m_is_pod_sandbox;
container["lookup_state"] = static_cast<int>(container_info.get_lookup_status());
container["created_time"] = static_cast<Json::Value::Int64>(container_info.m_created_time);
Expand Down
15 changes: 15 additions & 0 deletions userspace/libsinsp/container_engine/docker/async_source.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -897,6 +897,21 @@
{
container.m_privileged = privileged.asBool();
}
const Json::Value& host_pid = host_config_obj["PidMode"];
if(!host_pid.isNull() && host_pid.isString() && host_pid.asString() == "host")
{
container.m_host_pid = true;

Check warning on line 903 in userspace/libsinsp/container_engine/docker/async_source.cpp

View check run for this annotation

Codecov / codecov/patch

userspace/libsinsp/container_engine/docker/async_source.cpp#L903

Added line #L903 was not covered by tests
}
const Json::Value& host_net = host_config_obj["NetworkMode"];
if(!host_net.isNull() && host_net.isString() && host_net.asString() == "host")
{
container.m_host_network = true;

Check warning on line 908 in userspace/libsinsp/container_engine/docker/async_source.cpp

View check run for this annotation

Codecov / codecov/patch

userspace/libsinsp/container_engine/docker/async_source.cpp#L908

Added line #L908 was not covered by tests
}
const Json::Value& ipc_mode = host_config_obj["IpcMode"];
if(!ipc_mode.isNull() && ipc_mode.isString() && ipc_mode.asString() == "host")
{
container.m_host_ipc = true;

Check warning on line 913 in userspace/libsinsp/container_engine/docker/async_source.cpp

View check run for this annotation

Codecov / codecov/patch

userspace/libsinsp/container_engine/docker/async_source.cpp#L913

Added line #L913 was not covered by tests
}

parse_json_mounts(root["Mounts"], container.m_mounts);

Expand Down
6 changes: 6 additions & 0 deletions userspace/libsinsp/container_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,9 @@ class sinsp_container_info
m_type(CT_UNKNOWN),
m_container_ip(0),
m_privileged(false),
m_host_pid(false),
m_host_network(false),
m_host_ipc(false),
m_memory_limit(0),
m_swap_limit(0),
m_cpu_shares(1024),
Expand Down Expand Up @@ -316,6 +319,9 @@ class sinsp_container_info
std::string m_imagedigest;
uint32_t m_container_ip;
bool m_privileged;
bool m_host_pid;
bool m_host_network;
bool m_host_ipc;
std::vector<container_mount_info> m_mounts;
std::vector<container_port_mapping> m_port_mappings;
std::map<std::string, std::string> m_labels;
Expand Down
16 changes: 16 additions & 0 deletions userspace/libsinsp/cri.h
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,22 @@ template<class api> class cri_interface
const Json::Value &root,
sinsp_container_info &container);

/**
* @brief fill out pod sandbox network namespace mode info
* @param status `status` field of the PodSandboxStatusResponse
* @param container the container info to fill out
*/
void parse_cri_pod_sandbox_pid(const typename api::PodSandboxStatus &status,
sinsp_container_info &container);

/**
* @brief fill out pod sandbox ipc namespace mode info
* @param status `status` field of the PodSandboxStatusResponse
* @param container the container info to fill out
*/
void parse_cri_pod_sandbox_ipc(const typename api::PodSandboxStatus &status,
sinsp_container_info &container);


/////////////////////////////
// Generic parsers helpers
Expand Down
43 changes: 43 additions & 0 deletions userspace/libsinsp/cri.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,11 @@

bool priv_found = false;
const Json::Value *privileged = nullptr;

//
// Privileged flag
//

// old containerd?
if(walk_down_json(*linux, &privileged, "security_context", "privileged") && privileged->isBool())
{
Expand Down Expand Up @@ -647,6 +652,14 @@
const Json::Value &root,
sinsp_container_info &container)
{
//
// Pod network namespace mode
//
if (status.linux().namespaces().options().network() == api::NamespaceMode::NODE)
{
container.m_host_network = true;

Check warning on line 660 in userspace/libsinsp/cri.hpp

View check run for this annotation

Codecov / codecov/patch

userspace/libsinsp/cri.hpp#L660

Added line #L660 was not covered by tests
}

//
// Pod IP
//
Expand Down Expand Up @@ -726,6 +739,32 @@
return true;
}

template<typename api>
inline void cri_interface<api>::parse_cri_pod_sandbox_pid(const typename api::PodSandboxStatus &status,
sinsp_container_info &container)
{
//
// Pod pid namespace mode
//
if (status.linux().namespaces().options().pid() == api::NamespaceMode::NODE)
{
container.m_host_pid = true;
}
}

template<typename api>
inline void cri_interface<api>::parse_cri_pod_sandbox_ipc(const typename api::PodSandboxStatus &status,
sinsp_container_info &container)
{
//
// Pod ipc namespace mode
//
if (status.linux().namespaces().options().ipc() == api::NamespaceMode::NODE)
{
container.m_host_ipc = true;
}
}

///////////////////////////////////////////////////////////////////
// Main CRI parse entrypoint (make API calls and parse responses)
///////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -767,6 +806,8 @@
// add them as labels
parse_cri_labels(resp_pod_sandbox_container, container);
parse_cri_pod_sandbox_network(resp_pod_sandbox_container, root_pod_sandbox, container);
parse_cri_pod_sandbox_pid(resp_pod_sandbox_container, container);
parse_cri_pod_sandbox_ipc(resp_pod_sandbox_container, container);

Check warning on line 810 in userspace/libsinsp/cri.hpp

View check run for this annotation

Codecov / codecov/patch

userspace/libsinsp/cri.hpp#L810

Added line #L810 was not covered by tests
parse_cri_pod_sandbox_labels(resp_pod_sandbox_container, container);
return true;
}
Expand Down Expand Up @@ -850,6 +891,8 @@
const auto root_pod_sandbox = get_info_jvalue(resp_pod_sandbox_container_info);
// Add pod response network and labels to original container
parse_cri_pod_sandbox_network(resp_pod_sandbox_container, root_pod_sandbox, container);
parse_cri_pod_sandbox_pid(resp_pod_sandbox_container, container);
parse_cri_pod_sandbox_ipc(resp_pod_sandbox_container, container);

Check warning on line 895 in userspace/libsinsp/cri.hpp

View check run for this annotation

Codecov / codecov/patch

userspace/libsinsp/cri.hpp#L895

Added line #L895 was not covered by tests
parse_cri_pod_sandbox_labels(resp_pod_sandbox_container, container);
}

Expand Down
15 changes: 15 additions & 0 deletions userspace/libsinsp/parsers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5183,6 +5183,21 @@ void sinsp_parser::parse_container_json_evt(sinsp_evt *evt)
{
container_info->m_privileged = privileged.asBool();
}
const Json::Value& host_pid = container["host_pid"];
if(check_json_val_is_convertible(host_pid, Json::booleanValue, "host_pid"))
{
container_info->m_host_pid = host_pid.asBool();
}
const Json::Value& host_network = container["host_network"];
if(check_json_val_is_convertible(host_network, Json::booleanValue, "host_network"))
{
container_info->m_host_network = host_network.asBool();
}
const Json::Value& host_ipc = container["host_ipc"];
if(check_json_val_is_convertible(host_ipc, Json::booleanValue, "host_ipc"))
{
container_info->m_host_ipc = host_ipc.asBool();
}
const Json::Value& lookup_state = container["lookup_state"];
if(check_json_val_is_convertible(lookup_state, Json::uintValue, "lookup_state"))
{
Expand Down
41 changes: 41 additions & 0 deletions userspace/libsinsp/sinsp_filtercheck_container.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ static const filtercheck_field_info sinsp_filter_check_container_fields[] =
{PT_RELTIME, EPF_NONE, PF_DEC, "container.duration", "Number of nanoseconds since container.start_ts", "Number of nanoseconds since container.start_ts."},
{PT_CHARBUF, EPF_NONE, PF_NA, "container.ip", "Container ip address", "The container's / pod's primary ip address as retrieved from the container engine. Only ipv4 addresses are tracked. Consider container.cni.json (CRI use case) for logging ip addresses for each network interface. In instances of userspace container engine lookup delays, this field may not be available yet."},
{PT_CHARBUF, EPF_NONE, PF_NA, "container.cni.json", "Container's / pod's CNI result json", "The container's / pod's CNI result field from the respective pod status info. It contains ip addresses for each network interface exposed as unparsed escaped JSON string. Supported for CRI container engine (containerd, cri-o runtimes), optimized for containerd (some non-critical JSON keys removed). Useful for tracking ips (ipv4 and ipv6, dual-stack support) for each network interface (multi-interface support). In instances of userspace container engine lookup delays, this field may not be available yet."},
{PT_BOOL, EPF_NONE, PF_NA, "container.host_pid", "Host PID Namespace", "'true' if the process is running in the host PID namespace, 'false' otherwise."},
{PT_BOOL, EPF_NONE, PF_NA, "container.host_network", "Host Network Namespace", "'true' if the process is running in the host network namespace, 'false' otherwise."},
{PT_BOOL, EPF_NONE, PF_NA, "container.host_ipc", "Host IPC Namespace", "'true' if the process is running in the host IPC namespace, 'false' otherwise."},
};

sinsp_filter_check_container::sinsp_filter_check_container()
Expand Down Expand Up @@ -380,6 +383,44 @@ uint8_t* sinsp_filter_check_container::extract_single(sinsp_evt *evt, uint32_t*
m_val.u32 = (container_info->m_privileged ? 1 : 0);
}

RETURN_EXTRACT_VAR(m_val.u32);
break;
case TYPE_CONTAINER_HOST_PID:
case TYPE_CONTAINER_HOST_NETWORK:
case TYPE_CONTAINER_HOST_IPC:
if (tinfo->m_container_id.empty())
{
return NULL;
}
else
{
if(!container_info)
{
return NULL;
}

// Only return a true/false value for
// container types where we really know the
// host_pid status. // todo(loresuso): double check this
if (!is_docker_compatible(container_info->m_type))
{
return NULL;
}

if (m_field_id == TYPE_CONTAINER_HOST_NETWORK)
{
m_val.u32 = (container_info->m_host_network ? 1 : 0);
}
else if (m_field_id == TYPE_CONTAINER_HOST_IPC)
{
m_val.u32 = (container_info->m_host_ipc ? 1 : 0);
}
else if (m_field_id == TYPE_CONTAINER_HOST_PID)
{
m_val.u32 = (container_info->m_host_pid ? 1 : 0);
}
}

RETURN_EXTRACT_VAR(m_val.u32);
break;
case TYPE_CONTAINER_MOUNTS:
Expand Down
3 changes: 3 additions & 0 deletions userspace/libsinsp/sinsp_filtercheck_container.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ class sinsp_filter_check_container : public sinsp_filter_check
TYPE_CONTAINER_DURATION,
TYPE_CONTAINER_IP_ADDR,
TYPE_CONTAINER_CNIRESULT,
TYPE_CONTAINER_HOST_PID,
TYPE_CONTAINER_HOST_NETWORK,
TYPE_CONTAINER_HOST_IPC,
};

sinsp_filter_check_container();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -505,9 +505,9 @@ runtime::v1alpha2::PodSandboxStatusResponse get_default_cri_crio_pod_status_resp
// "linux": {
// "namespaces": {
// "options": {
// "ipc": "POD",
// "ipc": "NODE",
// "network": "POD",
// "pid": "CONTAINER",
// "pid": "NODE",
// "targetId": ""
// }
// }
Expand Down Expand Up @@ -535,6 +535,9 @@ runtime::v1alpha2::PodSandboxStatusResponse get_default_cri_crio_pod_status_resp
status->set_created_at((uint64_t)1676262698000004577); // dummy
status->mutable_metadata()->set_name("podsandbox1");
status->mutable_network()->set_ip("10.244.0.3");
status->mutable_linux()->mutable_namespaces()->mutable_options()->set_ipc(runtime::v1alpha2::NamespaceMode::NODE);
status->mutable_linux()->mutable_namespaces()->mutable_options()->set_network(runtime::v1alpha2::NamespaceMode::POD);
status->mutable_linux()->mutable_namespaces()->mutable_options()->set_pid(runtime::v1alpha2::NamespaceMode::NODE);
auto labels = status->mutable_labels();
(*labels)["app"] = "myapp";
(*labels)["example-label/custom_one"] = "mylabel";
Expand Down Expand Up @@ -620,6 +623,11 @@ TEST_F(sinsp_with_test_input, container_parser_cri_crio)
// Below retrieved from PodSandboxStatusResponse
res = cri_api_v1alpha2->parse_cri_pod_sandbox_network(resp_pod_sandbox_container, root_pod_sandbox, container);
ASSERT_TRUE(res);
ASSERT_FALSE(container.m_host_network);
cri_api_v1alpha2->parse_cri_pod_sandbox_pid(resp_pod_sandbox_container, container);
ASSERT_TRUE(container.m_host_pid);
cri_api_v1alpha2->parse_cri_pod_sandbox_ipc(resp_pod_sandbox_container, container);
ASSERT_TRUE(container.m_host_ipc);
res = cri_api_v1alpha2->parse_cri_pod_sandbox_labels(resp_pod_sandbox_container, container);
ASSERT_TRUE(res);

Expand Down Expand Up @@ -674,6 +682,9 @@ TEST_F(sinsp_with_test_input, container_parser_cri_crio)
ASSERT_EQ(get_field_as_string(evt, "container.image.digest"), "sha256:49ecc282021562c567a8159ef424a06cdd8637efdca5953de9794eafe29adcad");
ASSERT_EQ(get_field_as_string(evt, "container.ip"), "10.244.0.3");
ASSERT_EQ(get_field_as_string(evt, "container.cni.json"), "{\"cniVersion\":\"1.0.0\",\"interfaces\":[{\"name\":\"bridge\",\"mac\":\"ce:64:08:76:88:6a\"},{\"name\":\"veth71b0e931\",\"mac\":\"72:b7:4f:bc:e4:a4\"},{\"name\":\"eth0\",\"mac\":\"fe:06:00:f8:2f:4d\",\"sandbox\":\"/var/run/netns/dec735d1-0e86-44c1-94e0-a102173334a4\"}],\"ips\":[{\"interface\":2,\"address\":\"10.244.0.3/16\",\"gateway\":\"10.244.0.1\"}],\"routes\":[{\"dst\":\"0.0.0.0/0\",\"gw\":\"10.244.0.1\"}],\"dns\":{}}");
ASSERT_EQ(get_field_as_string(evt, "container.host_pid"), "true");
ASSERT_EQ(get_field_as_string(evt, "container.host_network"), "false");
ASSERT_EQ(get_field_as_string(evt, "container.host_ipc"), "true");

ASSERT_EQ(get_field_as_string(evt, "k8s.ns.name"), "redhat.test.crio");
ASSERT_EQ(get_field_as_string(evt, "k8s.pod.name"), "podsandbox1");
Expand Down
Loading