Skip to content

Commit

Permalink
detect containers on procfs
Browse files Browse the repository at this point in the history
Signed-off-by: qjerome <[email protected]>
  • Loading branch information
qjerome committed Feb 2, 2024
1 parent d2a1337 commit d459e20
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 17 deletions.
55 changes: 47 additions & 8 deletions kunai/src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ struct Task {
flags: u32,
resolved: HashMap<IpAddr, String>,
container: Option<Container>,
// needs to be vec because of procfs
cgroups: Vec<String>,
parent_key: Option<TaskKey>,
}

Expand Down Expand Up @@ -220,6 +222,34 @@ impl EventProcessor {
)
}
}

// we try to resolve containers from tasks found in procfs
for (tk, pk) in self
.tasks
.iter()
.map(|(&k, v)| (k, v.parent_key))
.collect::<Vec<(TaskKey, Option<TaskKey>)>>()
{
if let Some(parent) = pk {
if let Some(t) = self.tasks.get_mut(&tk) {
// trying to find container type in cgroups
t.container = Container::from_cgroups(&t.cgroups);
if t.container.is_some() {
// we don't need to do the ancestor's lookup
continue;
}
}

// lookup in ancestors
let ancestors = self.get_ancestors(parent);
if let Some(c) = Container::from_ancestors(&ancestors) {
self.tasks
.entry(tk)
.and_modify(|task| task.container = Some(c));
}
}
}

Ok(())
}

Expand Down Expand Up @@ -250,13 +280,22 @@ impl EventProcessor {
}
};

// we gather cgroups
let cgroups = p
.cgroups()?
.0
.into_iter()
.map(|cg| cg.pathname)
.collect::<Vec<String>>();

let task = Task {
image: image,
command_line: p.cmdline().unwrap_or(vec!["?".into()]),
pid: p.pid,
flags: stat.flags,
resolved: HashMap::new(),
container: None,
cgroups,
parent_key,
};

Expand Down Expand Up @@ -290,15 +329,14 @@ impl EventProcessor {
}

#[inline]
fn get_ancestors(&self, i: &StdEventInfo) -> Vec<String> {
let mut tk = i.parent_key();
fn get_ancestors(&self, mut parent: TaskKey) -> Vec<String> {
let mut ancestors = vec![];
let mut last = None;

while let Some(task) = self.tasks.get(&tk) {
while let Some(task) = self.tasks.get(&parent) {
last = Some(task);
ancestors.insert(0, task.image.to_string_lossy().to_string());
tk = match task.parent_key {
parent = match task.parent_key {
Some(v) => v,
None => {
break;
Expand All @@ -317,7 +355,7 @@ impl EventProcessor {

#[inline]
fn get_ancestors_string(&self, i: &StdEventInfo) -> String {
self.get_ancestors(i).join("|")
self.get_ancestors(i.parent_key()).join("|")
}

#[inline]
Expand Down Expand Up @@ -414,7 +452,7 @@ impl EventProcessor {
info: StdEventInfo,
event: &bpf_events::ExecveEvent,
) -> UserEvent<ExecveData> {
let ancestors = self.get_ancestors(&info);
let ancestors = self.get_ancestors(info.parent_key());

let opt_mnt_ns = Self::task_mnt_ns(&event.info);

Expand Down Expand Up @@ -838,8 +876,8 @@ impl EventProcessor {
let mut container_type = Container::from_cgroup(&cgroup);

if container_type.is_none() {
let ancestors = self.get_ancestors(&info);
container_type = Container::from_ancestors(ancestors);
let ancestors = self.get_ancestors(info.parent_key());
container_type = Container::from_ancestors(&ancestors);
}

let image = {
Expand All @@ -858,6 +896,7 @@ impl EventProcessor {
flags: info.info.process.flags,
resolved: HashMap::new(),
container: container_type,
cgroups: vec![cgroup.to_string()],
parent_key: Some(info.parent_key()),
});
}
Expand Down
31 changes: 22 additions & 9 deletions kunai/src/containers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use gene::FieldGetter;
use kunai_common::cgroup::Cgroup;
use kunai_macros::StrEnum;
use serde::{Deserialize, Serialize};
use std::path::{self};

#[derive(StrEnum, Debug, PartialEq, Clone, Copy)]
pub enum Container {
Expand Down Expand Up @@ -65,18 +66,15 @@ impl FieldGetter for Container {
}

impl Container {
#[inline]
pub fn from_cgroup(cgrp: &Cgroup) -> Option<Container> {
let s: Vec<String> = cgrp.to_vec();

if let Some(last) = s.last() {
if last.starts_with("docker-") {
fn from_split_cgroup<S: AsRef<str>>(cgroup: Vec<S>) -> Option<Container> {
if let Some(last) = cgroup.last() {
if last.as_ref().starts_with("docker-") {
return Some(Container::Docker);
}
}

if let Some(first) = s.get(1) {
if first.starts_with("lxc.payload.") {
if let Some(first) = cgroup.get(1) {
if first.as_ref().starts_with("lxc.payload.") {
return Some(Container::Lxc);
}
}
Expand All @@ -85,7 +83,22 @@ impl Container {
}

#[inline]
pub fn from_ancestors(ancestors: Vec<String>) -> Option<Container> {
pub fn from_cgroup(cgrp: &Cgroup) -> Option<Container> {
Self::from_split_cgroup(cgrp.to_vec())
}

#[inline]
pub fn from_cgroups(cgroups: &Vec<String>) -> Option<Container> {
for c in cgroups {
if let Some(c) = Self::from_split_cgroup(c.split(path::MAIN_SEPARATOR).collect()) {
return Some(c);
}
}
None
}

#[inline]
pub fn from_ancestors(ancestors: &Vec<String>) -> Option<Container> {
for a in ancestors {
match a.as_str() {
"/usr/bin/firejail" => return Some(Container::Firejail),
Expand Down

0 comments on commit d459e20

Please sign in to comment.