From 084d1dfb9838ca31fbdce07f1cc6e9669730aff3 Mon Sep 17 00:00:00 2001 From: Tom Weisshuhn Date: Sun, 19 Jan 2025 12:52:04 +0100 Subject: [PATCH] ebpf: track fd creations/destruction Signed-off-by: Tom Weisshuhn --- rust/backend/common/src/lib.rs | 22 +++++++ rust/backend/ebpf/README.md | 17 +++--- rust/backend/ebpf/src/lib.rs | 4 +- rust/backend/ebpf/src/sys_fd_tracking.rs | 78 ++++++++++++++++++++++++ 4 files changed, 112 insertions(+), 9 deletions(-) create mode 100644 rust/backend/ebpf/src/sys_fd_tracking.rs diff --git a/rust/backend/common/src/lib.rs b/rust/backend/common/src/lib.rs index 40ae1d9b..904aec67 100644 --- a/rust/backend/common/src/lib.rs +++ b/rust/backend/common/src/lib.rs @@ -131,6 +131,8 @@ impl SysSigquitCall { } } + +// garbage collection #[repr(C)] #[derive(Debug, Copy, Clone, CheckedBitPattern)] pub struct SysGcCall { @@ -139,6 +141,26 @@ pub struct SysGcCall { pub heap: Heap } + +// --------------------------------------- +// SysFdTracking: track the creation/ destruction of file descriptors + +#[repr(u8)] +#[derive(Debug, Copy, Clone, CheckedBitPattern)] +pub enum SysFdAction { + Created, + Destroyed, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone, CheckedBitPattern)] +pub struct SysFdActionCall { + pub pid: u32, + pub tid: u32, + pub time_stamp: u64, + pub fd_action: SysFdAction, +} + // ---------------------------------- // generate a unique id from pid and tid #[inline(always)] diff --git a/rust/backend/ebpf/README.md b/rust/backend/ebpf/README.md index 916a99ee..e7fd6416 100644 --- a/rust/backend/ebpf/README.md +++ b/rust/backend/ebpf/README.md @@ -9,14 +9,15 @@ SPDX-License-Identifier: MIT The entries in the maps are the structs defined in `../common/src/lib.rs`. The maps `_PIDS` are HashMaps that store the pid as key and as value the duration for a call to be considered blocking in nanosec. -For the features `SIGQUIT` and `JNIReferences` the durations are irrelevant as they are not relevant for the use-cases. +For the features `SIGQUIT` and `JNIReferences` the durations are irrelevant as they are not relevant for the use-cases. ## overview by hook name -| | type | functions to hook | map | -|---------------|------------|------------------------------------------------------------------------------|-------------------------------------| -| vfs_write | KProbe | `vfs_write`, `vfs_write_ret` | `VFS_WRITE_EVENTS` | -| sendmsg | Tracepoint | `sys_enter_sendmsg`, `sys_exit_sendmsg` | `SYS_SENDMSG_CALLS` | -| SIGQUIT | Tracepoint | `sys_sigquit` | `SYS_SIGQUIT_CALLS` | -| JNIReferences | UProbe | `trace_add_local`, `trace_del_local`, `trace_add_global`, `trace_del_global` | `JNI_REF_CALLS` | -| ... | ... | ... | ... | +| | type | functions to hook | map | +|---------------|------------|----------------------------------------------------------------------------|------------------------------------------| +| vfs_write | KProbe | `vfs_write`, `vfs_write_ret` | `VFS_WRITE_EVENTS` | +| sendmsg | Tracepoint | `sys_enter_sendmsg`, `sys_exit_sendmsg` | `SYS_SENDMSG_CALLS` | +| SIGQUIT | Tracepoint | `sys_sigquit` | `SYS_SIGQUIT_CALLS` | +| fd_tracking | Tracepoint | `sys_create_fd`, `sys_fd_destroy` | `SYS_FDTRACKING_EVENTS` | +| JNIReferences | UProbe | `trace_add_local`, `trace_del_local`, `trace_add_global`, `trace_del_global` | `JNI_REF_CALLS` | +| ... | ... | ... | ... | diff --git a/rust/backend/ebpf/src/lib.rs b/rust/backend/ebpf/src/lib.rs index b39f58d8..fa9151c9 100644 --- a/rust/backend/ebpf/src/lib.rs +++ b/rust/backend/ebpf/src/lib.rs @@ -3,6 +3,7 @@ // SPDX-FileCopyrightText: 2024 Benedikt Zinn // SPDX-FileCopyrightText: 2024 Felix Hilgers // SPDX-FileCopyrightText: 2024 Luca Bretting +// SPDX-FileCopyrightText: 2024 Tom Weisshuhn // // SPDX-License-Identifier: MIT @@ -12,4 +13,5 @@ pub mod vfs_write; pub mod sys_sendmsg; pub mod jni_references; pub mod sys_sigquit; -pub mod garbage_collection; \ No newline at end of file +pub mod garbage_collection; +pub mod sys_fd_tracking; \ No newline at end of file diff --git a/rust/backend/ebpf/src/sys_fd_tracking.rs b/rust/backend/ebpf/src/sys_fd_tracking.rs new file mode 100644 index 00000000..6e6ce3f3 --- /dev/null +++ b/rust/backend/ebpf/src/sys_fd_tracking.rs @@ -0,0 +1,78 @@ +// SPDX-FileCopyrightText: 2024 Tom Weisshuhn +// +// SPDX-License-Identifier: MIT + +use aya_ebpf::{helpers::gen::bpf_ktime_get_ns, macros::map, maps::RingBuf, programs::TracePointContext, EbpfContext}; +use aya_ebpf::maps::HashMap; +use aya_log_ebpf::error; +use backend_common::{SysFdAction, SysFdActionCall}; + +#[map(name = "SYS_FDTRACKING_PIDS")] +static SYS_FDTRACKING_PIDS: HashMap = HashMap::pinned(4096, 0); + +#[map(name = "SYS_FDTRACKING_EVENTS")] +pub static SYS_FDTRACKING_EVENTS: RingBuf = RingBuf::pinned(1024, 0); + +// Disclaimer: +// We have to swap here, because BPF_PROG_TEST_RUN does not support Tracepoints +// For testing we can set the prog-test flag and interpret it as TracepointContext, because we can set whatever we want +// For an example see backend/daemon/src/prog_test_run.rs + +#[cfg(feature = "prog-test")] +type Arg = aya_ebpf::programs::RawTracePointContext; + +#[cfg(not(feature = "prog-test"))] +type Arg = aya_ebpf::programs::TracePointContext; + +#[cfg_attr(feature = "prog-test", aya_ebpf::macros::raw_tracepoint)] +#[cfg_attr(not(feature = "prog-test"), aya_ebpf::macros::tracepoint)] +pub fn sys_create_fd(ctx: Arg) -> u32 { + let ctx = TracePointContext::new(ctx.as_ptr()); + handle_fd_action(ctx, SysFdAction::Created) +} + + +#[cfg_attr(feature = "prog-test", aya_ebpf::macros::raw_tracepoint)] +#[cfg_attr(not(feature = "prog-test"), aya_ebpf::macros::tracepoint)] +pub fn sys_destroy_fd(ctx: Arg) -> u32 { + let ctx = TracePointContext::new(ctx.as_ptr()); + handle_fd_action(ctx, SysFdAction::Destroyed) +} + + +fn handle_fd_action(ctx: TracePointContext, fd_action: SysFdAction) -> u32 { + let pid = ctx.pid(); + + if pid < 2700 { + return 1; + } + //if unsafe { SYS_FDTRACKING_PIDS.get(&pid).is_none() } { + // ignore signals from this pid + // return 0; + //} + + let tid = ctx.tgid(); + + let time_stamp: u64 = unsafe { bpf_ktime_get_ns() }; + + let mut entry = match SYS_FDTRACKING_EVENTS.reserve::(0) { + Some(entry) => entry, + None => { + error!(&ctx, "could not reserve space in map: SYS_FDTRACKING_CALLS"); + return 1; + } + }; + + let entry_mut = entry.as_mut_ptr(); + + unsafe { + (&raw mut (*entry_mut).pid).write(pid); + (&raw mut (*entry_mut).tid).write(tid); + (&raw mut (*entry_mut).time_stamp).write(time_stamp); + (&raw mut (*entry_mut).fd_action).write(fd_action); + } + + entry.submit(0); + + 0 +}