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

Merged
merged 7 commits into from
Oct 18, 2024
3 changes: 3 additions & 0 deletions userspace/libsinsp/container.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,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
12 changes: 12 additions & 0 deletions userspace/libsinsp/container_engine/docker/async_source.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,18 @@
if(!privileged.isNull() && privileged.isBool()) {
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 828 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#L828

Added line #L828 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 832 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#L832

Added line #L832 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 836 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#L836

Added line #L836 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 @@ -219,6 +219,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 @@ -265,6 +268,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 @@ -366,6 +366,22 @@ 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
40 changes: 40 additions & 0 deletions userspace/libsinsp/cri.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,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 @@ -628,6 +633,13 @@
const typename api::PodSandboxStatus &status,
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 640 in userspace/libsinsp/cri.hpp

View check run for this annotation

Codecov / codecov/patch

userspace/libsinsp/cri.hpp#L640

Added line #L640 was not covered by tests
}

//
// Pod IP
//
Expand Down Expand Up @@ -699,6 +711,30 @@
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 @@ -739,6 +775,8 @@
// elsewhere in the response and 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 779 in userspace/libsinsp/cri.hpp

View check run for this annotation

Codecov / codecov/patch

userspace/libsinsp/cri.hpp#L779

Added line #L779 was not covered by tests
parse_cri_pod_sandbox_labels(resp_pod_sandbox_container, container);
return true;
} else {
Expand Down Expand Up @@ -829,6 +867,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 871 in userspace/libsinsp/cri.hpp

View check run for this annotation

Codecov / codecov/patch

userspace/libsinsp/cri.hpp#L871

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

Expand Down
12 changes: 12 additions & 0 deletions userspace/libsinsp/parsers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4736,6 +4736,18 @@ void sinsp_parser::parse_container_json_evt(sinsp_evt *evt) {
if(check_json_val_is_convertible(privileged, Json::booleanValue, "privileged")) {
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")) {
container_info->set_lookup_status(
Expand Down
46 changes: 46 additions & 0 deletions userspace/libsinsp/sinsp_filtercheck_container.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,24 @@ static const filtercheck_field_info sinsp_filter_check_container_fields[] = {
"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 container is running in the host PID namespace, 'false' otherwise."},
{PT_BOOL,
EPF_NONE,
PF_NA,
"container.host_network",
"Host Network Namespace",
"'true' if the container is running in the host network namespace, 'false' otherwise."},
{PT_BOOL,
EPF_NONE,
PF_NA,
"container.host_ipc",
"Host IPC Namespace",
"'true' if the container is running in the host IPC namespace, 'false' otherwise."},
};

sinsp_filter_check_container::sinsp_filter_check_container() {
Expand Down Expand Up @@ -499,6 +517,34 @@ uint8_t *sinsp_filter_check_container::extract_single(sinsp_evt *evt,
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(is_host) {
return NULL;
} else {
if(!container_info) {
return NULL;
}

// Only return a true/false value for
// container types where we really know the
// host_pid, host_network, host_ipc status.
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 @@ -48,6 +48,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 @@ -507,9 +507,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 @@ -537,6 +537,12 @@ 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 @@ -632,6 +638,11 @@ TEST_F(sinsp_with_test_input, container_parser_cri_crio) {
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 @@ -775,13 +786,17 @@ 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