From 84621f1c23ac77b18c56349b1b3f02223a58c26c Mon Sep 17 00:00:00 2001 From: qjerome Date: Thu, 7 Nov 2024 16:43:22 +0100 Subject: [PATCH 1/8] chore: Release --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index de90852..22d1dc6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1426,7 +1426,7 @@ checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" [[package]] name = "kunai" -version = "0.3.0" +version = "0.3.1" dependencies = [ "anyhow", "aya", @@ -1465,7 +1465,7 @@ dependencies = [ [[package]] name = "kunai-common" -version = "0.3.0" +version = "0.3.1" dependencies = [ "aya", "aya-ebpf", @@ -1482,7 +1482,7 @@ dependencies = [ [[package]] name = "kunai-macros" -version = "0.3.0" +version = "0.3.1" dependencies = [ "proc-macro2", "quote", @@ -3390,7 +3390,7 @@ dependencies = [ [[package]] name = "xtask" -version = "0.3.0" +version = "0.3.1" dependencies = [ "anyhow", "clap", diff --git a/Cargo.toml b/Cargo.toml index f776551..2e17aed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ resolver = "2" members = ["kunai", "kunai-common", "xtask"] [workspace.package] -version = "0.3.0" +version = "0.3.1" edition = "2021" authors = ["Quentin JEROME "] license = "GPL-3.0" From 484801e73eb558bdd56f8bd052f8c00f6154c7ce Mon Sep 17 00:00:00 2001 From: qjerome Date: Thu, 7 Nov 2024 16:43:27 +0100 Subject: [PATCH 2/8] chore: Release kunai-ebpf version 0.3.1 --- kunai-ebpf/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kunai-ebpf/Cargo.toml b/kunai-ebpf/Cargo.toml index d911481..020dfe6 100644 --- a/kunai-ebpf/Cargo.toml +++ b/kunai-ebpf/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "kunai-ebpf" -version = "0.3.0" +version = "0.3.1" edition = "2021" description = "Package containing eBPF code used by Kunai" authors = ["Quentin JEROME "] From 1fa8d91c556ea956e9e8aeb226a82012d0da53bb Mon Sep 17 00:00:00 2001 From: qjerome Date: Mon, 11 Nov 2024 15:17:45 +0100 Subject: [PATCH 3/8] =?UTF-8?q?fix(main):=C2=A0show=20real=20ancestors=20a?= =?UTF-8?q?nd=20parent=5Fexe=20in=20events?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kunai/src/bin/main.rs | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/kunai/src/bin/main.rs b/kunai/src/bin/main.rs index 1778dab..0bc958c 100644 --- a/kunai/src/bin/main.rs +++ b/kunai/src/bin/main.rs @@ -89,7 +89,7 @@ struct Task { // needs to be vec because of procfs cgroups: Vec, nodename: Option, - parent_key: Option, + real_parent_key: Option, threads: HashSet, // flag telling if this task comes from procfs // parsing at kunai start @@ -555,7 +555,7 @@ impl<'s> EventConsumer<'s> { for (tk, pk) in self .tasks .iter() - .map(|(&k, v)| (k, v.parent_key)) + .map(|(&k, v)| (k, v.real_parent_key)) .collect::)>>() { if let Some(parent) = pk { @@ -625,7 +625,7 @@ impl<'s> EventConsumer<'s> { container: None, cgroups, nodename: None, - parent_key, + real_parent_key: parent_key, threads: HashSet::new(), procfs: true, exit: false, @@ -676,7 +676,7 @@ impl<'s> EventConsumer<'s> { skip -= 1; } - tk = match task.parent_key { + tk = match task.real_parent_key { Some(v) => v, None => { break; @@ -700,9 +700,11 @@ impl<'s> EventConsumer<'s> { #[inline(always)] fn get_parent_image(&self, i: &StdEventInfo) -> String { - let ck = i.parent_key(); + let ck = i.task_key(); self.tasks .get(&ck) + .and_then(|t| t.real_parent_key) + .and_then(|ptk| self.tasks.get(&ptk)) .map(|c| c.image.to_string_lossy().to_string()) .unwrap_or("?".into()) } @@ -789,12 +791,12 @@ impl<'s> EventConsumer<'s> { info: StdEventInfo, event: &bpf_events::ExecveEvent, ) -> UserEvent { - let ancestors = self.get_ancestors(info.parent_key(), 0); + let ancestors = self.get_ancestors_string(&info); let opt_mnt_ns = Self::task_mnt_ns(&event.info); let mut data = ExecveData { - ancestors: ancestors.join("|"), + ancestors, parent_exe: self.get_parent_image(&info), command_line: event.data.argv.to_command_line(), exe: self.get_hashes_with_ns(opt_mnt_ns, &cache::Path::from(&event.data.executable)), @@ -1323,10 +1325,14 @@ impl<'s> EventConsumer<'s> { event: &bpf_events::CorrelationEvent, ) { let ck = info.task_key(); + let mut parent_key = info.parent_key(); // Execve must remove any previous task (i.e. coming from // clone or tasksched for instance) if matches!(event.data.origin, Type::Execve | Type::ExecveScript) { + if let Some(p) = self.tasks.get(&ck).and_then(|t| t.real_parent_key) { + parent_key = p; + } self.tasks.remove(&ck); } @@ -1372,7 +1378,7 @@ impl<'s> EventConsumer<'s> { let mut container_type = Container::from_cgroups(&cgroups); if container_type.is_none() { - let ancestors = self.get_ancestors(info.parent_key(), 0); + let ancestors = self.get_ancestors(parent_key, 0); container_type = Container::from_ancestors(&ancestors); } @@ -1387,7 +1393,7 @@ impl<'s> EventConsumer<'s> { // we update parent's information if matches!(event.data.origin, Type::Clone) { // the source is a Clone event so our task has spawned a child thread - self.tasks.entry(info.parent_key()).and_modify(|e| { + self.tasks.entry(parent_key).and_modify(|e| { e.threads.insert(info.task_key()); }); } @@ -1402,7 +1408,7 @@ impl<'s> EventConsumer<'s> { container: container_type, cgroups, nodename: event.data.nodename(), - parent_key: Some(info.parent_key()), + real_parent_key: Some(parent_key), threads: HashSet::new(), procfs: false, exit: false, From 00976b5ee16f7ad4fa2e4cc86495e3ea55b2364e Mon Sep 17 00:00:00 2001 From: qjerome Date: Mon, 11 Nov 2024 22:18:14 +0100 Subject: [PATCH 4/8] add(common): zombie member in TaskInfo --- kunai-common/src/bpf_events.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kunai-common/src/bpf_events.rs b/kunai-common/src/bpf_events.rs index 51626fd..2a8acad 100644 --- a/kunai-common/src/bpf_events.rs +++ b/kunai-common/src/bpf_events.rs @@ -167,6 +167,8 @@ pub struct Namespaces { #[repr(C)] #[derive(Debug, Default, Clone, Copy)] pub struct TaskInfo { + // this flag is used/set in userland only + pub zombie: bool, pub flags: u32, pub comm: [u8; COMM_SIZE], pub uid: u32, From 9c2ad3298ab2280c715d3c7bf286a6f6b7c89b39 Mon Sep 17 00:00:00 2001 From: qjerome Date: Mon, 11 Nov 2024 22:31:37 +0100 Subject: [PATCH 5/8] feat: zombie tasks tracking --- kunai/src/bin/main.rs | 78 ++++++++++++++++++++++++++++++++++--------- kunai/src/events.rs | 22 ++++++------ kunai/src/info.rs | 20 ++++++++--- 3 files changed, 89 insertions(+), 31 deletions(-) diff --git a/kunai/src/bin/main.rs b/kunai/src/bin/main.rs index 0bc958c..4f75673 100644 --- a/kunai/src/bin/main.rs +++ b/kunai/src/bin/main.rs @@ -25,7 +25,7 @@ use kunai::util::uname::Utsname; use kunai::yara::{Scanner, SourceCode}; use kunai::{cache, util}; use kunai_common::bpf_events::{ - self, error, event, mut_event, EncodedEvent, Event, PrctlOption, Signal, Type, + self, error, event, mut_event, EncodedEvent, Event, PrctlOption, Signal, TaskInfo, Type, MAX_BPF_EVENT_SIZE, }; use kunai_common::config::Filter; @@ -89,8 +89,13 @@ struct Task { // needs to be vec because of procfs cgroups: Vec, nodename: Option, + // this is the TaskKey retrieved from eBPF + parent_key: Option, + // this is the TaskKey from correlation real_parent_key: Option, threads: HashSet, + // ebpf task info for this task + kernel_task_info: Option, // flag telling if this task comes from procfs // parsing at kunai start procfs: bool, @@ -104,6 +109,11 @@ impl Task { self.flags & 0x00200000 == 0x00200000 } + #[inline(always)] + fn is_zombie(&self) -> bool { + self.parent_key.is_some() && self.parent_key != self.real_parent_key + } + #[inline(always)] fn command_line_string(&self) -> String { self.command_line.join(" ") @@ -625,7 +635,9 @@ impl<'s> EventConsumer<'s> { container: None, cgroups, nodename: None, + parent_key, real_parent_key: parent_key, + kernel_task_info: None, threads: HashSet::new(), procfs: true, exit: false, @@ -1262,7 +1274,7 @@ impl<'s> EventConsumer<'s> { let etype = event.ty(); // cleanup tasks when process exits - if (matches!(etype, Type::Exit) && info.info.process.pid == info.info.process.tgid) + if (matches!(etype, Type::Exit) && info.task_info().pid == info.task_info().tgid) || matches!(etype, Type::ExitGroup) { let tk = info.task_key(); @@ -1354,7 +1366,7 @@ impl<'s> EventConsumer<'s> { None => vec![cgroup.to_string()], Some(_) => { if let Ok(cgroups) = - procfs::process::Process::new(info.info.process.pid).and_then(|p| p.cgroups()) + procfs::process::Process::new(info.task_info().pid).and_then(|p| p.cgroups()) { // we return cgroup from procfs cgroups @@ -1366,8 +1378,8 @@ impl<'s> EventConsumer<'s> { // we report an error warn!( "failed to resolve cgroup for pid={} guuid={}", - info.info.process.pid, - info.info.process.tg_uuid.into_uuid().hyphenated() + info.task_info().pid, + info.task_info().tg_uuid.into_uuid().hyphenated() ); // still get a chance to do something with cgroup vec![cgroup.to_string()] @@ -1383,7 +1395,7 @@ impl<'s> EventConsumer<'s> { } let image = { - if info.info.process.is_kernel_thread() { + if info.task_info().is_kernel_thread() { KERNEL_IMAGE.into() } else { event.data.exe.to_path_buf() @@ -1402,13 +1414,15 @@ impl<'s> EventConsumer<'s> { self.tasks.entry(ck).or_insert(Task { image, command_line: event.data.argv.to_argv(), - pid: info.info.process.tgid, - flags: info.info.process.flags, + pid: info.task_info().tgid, + flags: info.task_info().flags, resolved: HashMap::new(), container: container_type, cgroups, nodename: event.data.nodename(), + parent_key: Some(info.parent_key()), real_parent_key: Some(parent_key), + kernel_task_info: Some(*info.task_info()), threads: HashSet::new(), procfs: false, exit: false, @@ -1417,7 +1431,7 @@ impl<'s> EventConsumer<'s> { #[inline(always)] fn handle_hash_event(&mut self, info: StdEventInfo, event: &bpf_events::HashEvent) { - let opt_mnt_ns = Self::task_mnt_ns(&info.info); + let opt_mnt_ns = Self::task_mnt_ns(&info.bpf); self.get_hashes_with_ns(opt_mnt_ns, &cache::Path::from(&event.data.path)); } @@ -1425,9 +1439,40 @@ impl<'s> EventConsumer<'s> { fn build_std_event_info(&mut self, i: bpf_events::EventInfo) -> StdEventInfo { let opt_mnt_ns = Self::task_mnt_ns(&i); - let std_info = StdEventInfo::from_bpf(i, self.random); + let mut std_info = StdEventInfo::from_bpf(i, self.random); + + // we need to find if task is a zombie and replace + // its parent with the real one if needed + if let Some(kti) = self + .tasks + .get(&std_info.task_key()) + .and_then(|t| { + if !t.is_zombie() { + None + } else { + t.real_parent_key + } + }) + // we get real parent + .and_then(|tk| self.tasks.get(&tk)) + // we get real parent's TaskInfo + .and_then(|t| t.kernel_task_info) + { + // if we arrive here, this means the task is a zombie + // and we need to replace its parent by the real one + std_info.bpf.parent = kti; + std_info.bpf.process.zombie = true + } - let cd = self.tasks.get(&std_info.task_key()); + // we must set the zombie flag of the parent if needed + if self + .tasks + .get(&std_info.parent_key()) + .map(|t| t.is_zombie()) + .unwrap_or_default() + { + std_info.bpf.parent.zombie = true + } let host = kunai::info::HostInfo { name: self.system_info.hostname.clone(), @@ -1438,9 +1483,10 @@ impl<'s> EventConsumer<'s> { if let Some(mnt_ns) = opt_mnt_ns { if mnt_ns != self.system_info.mount_ns { + let t = self.tasks.get(&std_info.task_key()); container = Some(kunai::info::ContainerInfo { - name: cd.and_then(|t| t.nodename.clone()).unwrap_or("?".into()), - ty: cd.and_then(|cd| cd.container), + name: t.and_then(|t| t.nodename.clone()).unwrap_or("?".into()), + ty: t.and_then(|cd| cd.container), }); } } @@ -1690,10 +1736,10 @@ impl<'s> EventConsumer<'s> { &bpf_events::CorrelationEvent::from(e), ); - if self.filter.is_enabled(std_info.info.etype) { + if self.filter.is_enabled(std_info.bpf.etype) { // we have to rebuild std_info as it has it is uses correlation // information - let std_info = self.build_std_event_info(std_info.info); + let std_info = self.build_std_event_info(std_info.bpf); let mut e = self.execve_event(std_info, e); self.scan_and_print(&mut e); @@ -1716,7 +1762,7 @@ impl<'s> EventConsumer<'s> { if self.filter.is_enabled(Type::Clone) { // we have to rebuild std_info as it has it is uses correlation // information - let std_info = self.build_std_event_info(std_info.info); + let std_info = self.build_std_event_info(std_info.bpf); let mut e = self.clone_event(std_info, e); self.scan_and_print(&mut e); } diff --git a/kunai/src/events.rs b/kunai/src/events.rs index 2f99e12..774b874 100644 --- a/kunai/src/events.rs +++ b/kunai/src/events.rs @@ -68,10 +68,10 @@ impl From<&StdEventInfo> for EventSection { fn from(value: &StdEventInfo) -> Self { Self { source: "kunai".into(), - id: value.info.etype.id(), - name: value.info.etype.to_string(), - uuid: value.info.uuid.into_uuid().hyphenated().to_string(), - batch: value.info.batch, + id: value.bpf.etype.id(), + name: value.bpf.etype.to_string(), + uuid: value.bpf.uuid.into_uuid().hyphenated().to_string(), + batch: value.bpf.batch, } } } @@ -98,6 +98,7 @@ pub struct TaskSection { pub namespaces: Option, #[serde(with = "u32_hex")] pub flags: u32, + pub zombie: bool, } impl From for TaskSection { @@ -111,6 +112,7 @@ impl From for TaskSection { gid: value.gid, namespaces: value.namespaces.map(|ns| ns.into()), flags: value.flags, + zombie: value.zombie, } } } @@ -196,13 +198,13 @@ impl From for EventInfo { }, event: EventSection { source: "kunai".into(), - id: value.info.etype.id(), - name: value.info.etype.to_string(), - uuid: value.info.uuid.into_uuid().hyphenated().to_string(), - batch: value.info.batch, + id: value.bpf.etype.id(), + name: value.bpf.etype.to_string(), + uuid: value.bpf.uuid.into_uuid().hyphenated().to_string(), + batch: value.bpf.batch, }, - task: value.info.process.into(), - parent_task: value.info.parent.into(), + task: value.bpf.process.into(), + parent_task: value.bpf.parent.into(), utc_time: value.utc_timestamp.into(), } } diff --git a/kunai/src/info.rs b/kunai/src/info.rs index 35d4e86..84a5b89 100644 --- a/kunai/src/info.rs +++ b/kunai/src/info.rs @@ -2,7 +2,7 @@ use std::io; use chrono::{DateTime, Utc}; use kunai_common::{ - bpf_events::{self, EventInfo}, + bpf_events::{self, EventInfo, TaskInfo}, uuid::TaskUuid, }; use thiserror::Error; @@ -68,20 +68,30 @@ pub struct AdditionalInfo { #[derive(Default, Debug, Clone)] pub struct StdEventInfo { - pub info: bpf_events::EventInfo, + pub bpf: bpf_events::EventInfo, pub additional: AdditionalInfo, pub utc_timestamp: DateTime, } impl StdEventInfo { + #[inline(always)] + pub fn task_info(&self) -> &TaskInfo { + &self.bpf.process + } + + #[inline(always)] + pub fn parent_info(&self) -> &TaskInfo { + &self.bpf.parent + } + #[inline(always)] pub fn task_key(&self) -> TaskKey { - TaskKey::from(self.info.process.tg_uuid) + TaskKey::from(self.task_info().tg_uuid) } #[inline(always)] pub fn parent_key(&self) -> TaskKey { - TaskKey::from(self.info.parent.tg_uuid) + TaskKey::from(self.parent_info().tg_uuid) } #[inline] @@ -90,7 +100,7 @@ impl StdEventInfo { info.set_uuid_random(rand); StdEventInfo { - info, + bpf: info, // on older kernels bpf_ktime_get_boot_ns() is not available so it is not // easy to compute correct event timestamp from eBPF so utc_timestamp is // the time at which the event is processed. From d40e003bbbeab03e5fbfe98706a82f9fff613629 Mon Sep 17 00:00:00 2001 From: qjerome Date: Tue, 12 Nov 2024 14:07:15 +0100 Subject: [PATCH 6/8] fix(main): minor change in zombie attribution --- kunai/src/bin/main.rs | 6 +++--- kunai/src/info.rs | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/kunai/src/bin/main.rs b/kunai/src/bin/main.rs index 4f75673..a41837d 100644 --- a/kunai/src/bin/main.rs +++ b/kunai/src/bin/main.rs @@ -1447,10 +1447,10 @@ impl<'s> EventConsumer<'s> { .tasks .get(&std_info.task_key()) .and_then(|t| { - if !t.is_zombie() { - None - } else { + if t.real_parent_key.is_some() && t.real_parent_key != Some(std_info.parent_key()) { t.real_parent_key + } else { + None } }) // we get real parent diff --git a/kunai/src/info.rs b/kunai/src/info.rs index 84a5b89..5066a92 100644 --- a/kunai/src/info.rs +++ b/kunai/src/info.rs @@ -16,6 +16,7 @@ pub struct TaskKey { } impl From for TaskKey { + #[inline(always)] fn from(value: TaskUuid) -> Self { // in task_struct start_time has a higher resolution so we need to scale it // down in order to have a comparable value with the procfs one @@ -36,6 +37,7 @@ pub enum KeyError { impl TryFrom<&procfs::process::Process> for TaskKey { type Error = KeyError; + #[inline(always)] fn try_from(p: &procfs::process::Process) -> Result { let stat = p.stat()?; // panic here if we cannot get CLK_TCK From 27009893a4eae9661057eb5df593af0491a7e81e Mon Sep 17 00:00:00 2001 From: qjerome Date: Mon, 18 Nov 2024 10:35:45 +0100 Subject: [PATCH 7/8] chore: upgrade fs-walk --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 22d1dc6..95a252a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1070,9 +1070,9 @@ checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" [[package]] name = "fs-walk" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445ee222cddb7095a1c08f94b6fe4926e2c93b389c4f71b65ab38bfa19227f48" +checksum = "b916d76dbd9446be6a7266359cf633cad350b61a96ac7ff936d13c24f88cf4bc" [[package]] name = "fs4" From 2c135a0637ce19e735907d25da64c8a62e47d0b2 Mon Sep 17 00:00:00 2001 From: qjerome Date: Mon, 18 Nov 2024 10:39:21 +0100 Subject: [PATCH 8/8] refactor: improve zombie tracking --- kunai/src/bin/main.rs | 58 +++++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/kunai/src/bin/main.rs b/kunai/src/bin/main.rs index a41837d..0499ab7 100644 --- a/kunai/src/bin/main.rs +++ b/kunai/src/bin/main.rs @@ -89,17 +89,20 @@ struct Task { // needs to be vec because of procfs cgroups: Vec, nodename: Option, - // this is the TaskKey retrieved from eBPF - parent_key: Option, // this is the TaskKey from correlation real_parent_key: Option, threads: HashSet, // ebpf task info for this task kernel_task_info: Option, + // execve state of the task + execved: bool, // flag telling if this task comes from procfs // parsing at kunai start procfs: bool, + // exit state of the task exit: bool, + // zombie state of the task + zombie: bool, } impl Task { @@ -109,11 +112,6 @@ impl Task { self.flags & 0x00200000 == 0x00200000 } - #[inline(always)] - fn is_zombie(&self) -> bool { - self.parent_key.is_some() && self.parent_key != self.real_parent_key - } - #[inline(always)] fn command_line_string(&self) -> String { self.command_line.join(" ") @@ -468,6 +466,7 @@ impl<'s> EventConsumer<'s> { .extension("kunai") .extension("gen") .extension("gene") + .sort(true) // don't go recursive .max_depth(0); @@ -635,12 +634,13 @@ impl<'s> EventConsumer<'s> { container: None, cgroups, nodename: None, - parent_key, real_parent_key: parent_key, kernel_task_info: None, threads: HashSet::new(), + execved: true, procfs: true, exit: false, + zombie: false, }; self.tasks.insert(tk, task); @@ -1291,7 +1291,13 @@ impl<'s> EventConsumer<'s> { // in case on exit_group we need to clean child // threads properly if matches!(etype, Type::ExitGroup) { - remove_threads.extend(t.threads.clone()); + remove_threads.extend( + t.threads + .iter() + // we must remove only threads that did not execve-d + .filter(|&t| self.tasks.get(t).map(|t| !t.execved).unwrap_or_default()) + .clone(), + ); } if t.threads.is_empty() && !t.procfs { @@ -1338,11 +1344,13 @@ impl<'s> EventConsumer<'s> { ) { let ck = info.task_key(); let mut parent_key = info.parent_key(); + let execve_flag = matches!(event.data.origin, Type::Execve | Type::ExecveScript); // Execve must remove any previous task (i.e. coming from // clone or tasksched for instance) - if matches!(event.data.origin, Type::Execve | Type::ExecveScript) { + if execve_flag { if let Some(p) = self.tasks.get(&ck).and_then(|t| t.real_parent_key) { + // we keep track of real parent_key in case of zombie task parent_key = p; } self.tasks.remove(&ck); @@ -1420,12 +1428,13 @@ impl<'s> EventConsumer<'s> { container: container_type, cgroups, nodename: event.data.nodename(), - parent_key: Some(info.parent_key()), real_parent_key: Some(parent_key), kernel_task_info: Some(*info.task_info()), threads: HashSet::new(), + execved: execve_flag, procfs: false, exit: false, + zombie: false, }); } @@ -1436,18 +1445,20 @@ impl<'s> EventConsumer<'s> { } #[inline(always)] - fn build_std_event_info(&mut self, i: bpf_events::EventInfo) -> StdEventInfo { - let opt_mnt_ns = Self::task_mnt_ns(&i); - - let mut std_info = StdEventInfo::from_bpf(i, self.random); - + fn track_zombie_task(&mut self, std_info: &mut StdEventInfo) { // we need to find if task is a zombie and replace // its parent with the real one if needed if let Some(kti) = self .tasks - .get(&std_info.task_key()) + .get_mut(&std_info.task_key()) .and_then(|t| { - if t.real_parent_key.is_some() && t.real_parent_key != Some(std_info.parent_key()) { + if t.zombie + || (t.real_parent_key.is_some() + && t.real_parent_key != Some(std_info.parent_key())) + { + // task is a zombie + t.zombie = true; + // we must continue with the real parent task key t.real_parent_key } else { None @@ -1468,11 +1479,18 @@ impl<'s> EventConsumer<'s> { if self .tasks .get(&std_info.parent_key()) - .map(|t| t.is_zombie()) + .map(|t| t.zombie) .unwrap_or_default() { std_info.bpf.parent.zombie = true } + } + + #[inline(always)] + fn build_std_event_info(&mut self, i: bpf_events::EventInfo) -> StdEventInfo { + let opt_mnt_ns = Self::task_mnt_ns(&i); + + let mut std_info = StdEventInfo::from_bpf(i, self.random); let host = kunai::info::HostInfo { name: self.system_info.hostname.clone(), @@ -1491,6 +1509,8 @@ impl<'s> EventConsumer<'s> { } } + self.track_zombie_task(&mut std_info); + std_info.with_additional_info(AdditionalInfo { host, container }) }