diff options
| author | Baitinq <[email protected]> | 2024-07-22 22:43:00 +0200 |
|---|---|---|
| committer | Baitinq <[email protected]> | 2024-07-22 22:43:00 +0200 |
| commit | d9ad9d226fd4613509c73b99e13f11606c10ff0d (patch) | |
| tree | 54e25ba99e915e0905d272ad5e293958a38fc7db | |
| parent | fs-tracer: open files should be referenced with pid+fd (diff) | |
| download | fs-tracer-d9ad9d226fd4613509c73b99e13f11606c10ff0d.tar.gz fs-tracer-d9ad9d226fd4613509c73b99e13f11606c10ff0d.tar.bz2 fs-tracer-d9ad9d226fd4613509c73b99e13f11606c10ff0d.zip | |
fs-tracer: handle close syscall and properly serialize reqs
| -rw-r--r-- | TODO | 1 | ||||
| -rw-r--r-- | fs-tracer-common/src/lib.rs | 21 | ||||
| -rw-r--r-- | fs-tracer-ebpf/src/main.rs | 5 | ||||
| -rw-r--r-- | fs-tracer-ebpf/src/syscalls/close.rs | 57 | ||||
| -rw-r--r-- | fs-tracer-ebpf/src/syscalls/mod.rs | 2 | ||||
| -rw-r--r-- | fs-tracer-ebpf/src/syscalls/write.rs | 2 | ||||
| -rw-r--r-- | fs-tracer/src/main.rs | 44 | ||||
| -rw-r--r-- | fs-tracer/src/syscall_handler.rs | 50 | ||||
| -rwxr-xr-x | tests/a.out | bin | 15872 -> 15872 bytes | |||
| -rw-r--r-- | tests/openat.c | 15 | ||||
| -rw-r--r-- | tests/testfile | 5 |
11 files changed, 153 insertions, 49 deletions
diff --git a/TODO b/TODO index 47d6516..1c3ecce 100644 --- a/TODO +++ b/TODO @@ -1 +1,2 @@ put agent in docker +it seems like openat is not the only active syscall there is? diff --git a/fs-tracer-common/src/lib.rs b/fs-tracer-common/src/lib.rs index 3615dec..fb36b74 100644 --- a/fs-tracer-common/src/lib.rs +++ b/fs-tracer-common/src/lib.rs @@ -15,6 +15,7 @@ use crate::vmlinux::umode_t; pub enum SyscallInfo { Write(WriteSyscallBPF), Open(OpenSyscallBPF), + Close(CloseSyscallBPF), } #[derive(Clone, Copy)] @@ -67,3 +68,23 @@ impl fmt::Debug for OpenSyscallBPF { .finish() } } + +#[derive(Clone, Copy)] +pub struct CloseSyscallBPF { + pub pid: u32, + pub fd: c_int, + + pub ret: c_long, +} + +unsafe impl Sync for CloseSyscallBPF {} + +impl fmt::Debug for CloseSyscallBPF { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("CloseSyscallBPF") + .field("pid", &self.pid) + .field("fd", &self.fd) + .field("ret", &self.ret) + .finish() + } +} diff --git a/fs-tracer-ebpf/src/main.rs b/fs-tracer-ebpf/src/main.rs index 8287a7f..a6794f5 100644 --- a/fs-tracer-ebpf/src/main.rs +++ b/fs-tracer-ebpf/src/main.rs @@ -68,11 +68,8 @@ fn handle_syscall( /*8 => { Ok(0) //handle_sys_lseek(ctx); - } - 3 => { - Ok(0) - //handle_sys_close(ctx); }*/ + 3 => syscalls::close::handle_sys_close(ctx, syscall_type), _ => { info!(&ctx, "unhandled syscall: {}", syscall_nr); Err(1) diff --git a/fs-tracer-ebpf/src/syscalls/close.rs b/fs-tracer-ebpf/src/syscalls/close.rs new file mode 100644 index 0000000..020ad64 --- /dev/null +++ b/fs-tracer-ebpf/src/syscalls/close.rs @@ -0,0 +1,57 @@ +use aya_ebpf::{ + cty::{c_char, c_uint}, + helpers::{bpf_probe_read_kernel_str_bytes, bpf_probe_read_user_str_bytes}, +}; +use core::ffi::c_size_t; +use fs_tracer_common::CloseSyscallBPF; + +use crate::*; + +pub fn handle_sys_close( + ctx: TracePointContext, + syscall_type: SyscallType, +) -> Result<c_long, c_long> { + match syscall_type { + SyscallType::Enter => unsafe { handle_sys_close_enter(ctx) }, + SyscallType::Exit => unsafe { handle_sys_close_exit(ctx) }, + } +} + +unsafe fn handle_sys_close_enter(ctx: TracePointContext) -> Result<c_long, c_long> { + info!(&ctx, "handle_sys_close start"); + #[repr(C)] + #[derive(Clone, Copy)] + struct CloseSyscallArgs { + fd: c_int, + } + let args = ctx.read_at::<CloseSyscallArgs>(16)?; + let tgid: u32 = ctx.tgid(); + let _ = SYSCALL_ENTERS.insert( + &tgid, + &SyscallInfo::Close(CloseSyscallBPF { + pid: ctx.pid(), + fd: args.fd, + ret: -9999, + }), + 0, + ); + + Ok(0) +} + +unsafe fn handle_sys_close_exit(ctx: TracePointContext) -> Result<c_long, c_long> { + info!(&ctx, "handle_sys_close_exit start"); + let ret = ctx.read_at::<c_long>(16)?; //TODO: We cant use unwrap, thats why we couldnt use the aya helper fns + + let tgid = ctx.tgid(); + if let Some(syscall) = SYSCALL_ENTERS.get(&tgid) + && let SyscallInfo::Close(mut syscall_close) = syscall + { + syscall_close.ret = ret; + EVENTS.output(&ctx, &SyscallInfo::Close(syscall_close), 0); + let _ = SYSCALL_ENTERS.remove(&tgid); + return Ok(0); + } + + Err(0) +} diff --git a/fs-tracer-ebpf/src/syscalls/mod.rs b/fs-tracer-ebpf/src/syscalls/mod.rs index de2224a..8661535 100644 --- a/fs-tracer-ebpf/src/syscalls/mod.rs +++ b/fs-tracer-ebpf/src/syscalls/mod.rs @@ -1,3 +1,3 @@ +pub mod close; pub mod open; pub mod write; - diff --git a/fs-tracer-ebpf/src/syscalls/write.rs b/fs-tracer-ebpf/src/syscalls/write.rs index 951b297..6010dce 100644 --- a/fs-tracer-ebpf/src/syscalls/write.rs +++ b/fs-tracer-ebpf/src/syscalls/write.rs @@ -1,5 +1,3 @@ -#![feature(let_chains)] - use aya_ebpf::{ cty::{c_char, c_uint}, helpers::{bpf_probe_read_kernel_str_bytes, bpf_probe_read_user_str_bytes}, diff --git a/fs-tracer/src/main.rs b/fs-tracer/src/main.rs index 815a9e0..1f9626c 100644 --- a/fs-tracer/src/main.rs +++ b/fs-tracer/src/main.rs @@ -8,6 +8,7 @@ use bytes::BytesMut; use core::panic; use fs_tracer_common::SyscallInfo; use log::{debug, info, warn}; +use serde::Serialize; use std::env; use std::sync::{ atomic::{AtomicBool, Ordering}, @@ -56,13 +57,14 @@ async fn main() -> Result<(), anyhow::Error> { trace_enters_program.attach("syscalls", "sys_enter_write")?; // program.attach("syscalls", "sys_exit_write")?; //trace_enters_program.attach("syscalls", "sys_enter_lseek")?; - //program.attach("syscalls", "sys_enter_close")?; + trace_enters_program.attach("syscalls", "sys_enter_close")?; let trace_exits_program: &mut TracePoint = bpf.program_mut("fs_tracer_exit").unwrap().try_into()?; trace_exits_program.load()?; trace_exits_program.attach("syscalls", "sys_exit_openat")?; trace_exits_program.attach("syscalls", "sys_exit_write")?; + trace_exits_program.attach("syscalls", "sys_exit_close")?; println!("Num of cpus: {}", online_cpus()?.len()); @@ -108,39 +110,49 @@ async fn main() -> Result<(), anyhow::Error> { drop(resolved_files_send); - let mut request_body = String::from("["); + let mut resolved_files_for_request: Vec<FSTracerFile> = vec![]; for elt in &resolved_files_recv { - request_body.push_str(&elt); - request_body.push_str(","); - // 1000000 bytes = 1MB (max kafka message size) - if request_body.len() < 999999 { + info!("HELLO123!"); + if elt.absolute_path.starts_with("/proc/") { + continue; + } + resolved_files_for_request.push(elt); + if resolved_files_for_request.len() < 40 { + //TODO: This is not good, maybe time + //based? continue; } - request_body.pop(); // remove trailing ',' - request_body.push_str("]"); - send_request(&url, &fs_tracer_api_key, &request_body); - info!("SENT REQUEST! {:?}", request_body); - request_body = String::from("["); + info!("SENDING REQUEST!"); + send_request(&url, &fs_tracer_api_key, &resolved_files_for_request); + resolved_files_for_request.clear(); } info!("All threads stopped, exiting now..."); - if !request_body.len() > 1 { - request_body.push_str("]"); - send_request(&url, &fs_tracer_api_key, &request_body); + if !resolved_files_for_request.len() > 1 { + send_request(&url, &fs_tracer_api_key, &resolved_files_for_request); } Ok(()) } -fn send_request(url: &str, fs_tracer_api_key: &str, request_body: &str) { +#[derive(Serialize, Debug)] +struct FSTracerFile { + timestamp: String, + absolute_path: String, + contents: String, +} + +fn send_request(url: &str, fs_tracer_api_key: &str, files: &Vec<FSTracerFile>) { //TODO: Retries + let serialized_body = serde_json::to_string(files).unwrap(); let resp = ureq::post(&url) .set("API_KEY", &fs_tracer_api_key) - .send_string(&request_body) + .send_string(&serialized_body) .expect("Failed to send request"); if resp.status() != 200 { panic!("Failed to send request: {:?}", resp); } + info!("SENT REQUEST! {:?}", serialized_body); } diff --git a/fs-tracer/src/syscall_handler.rs b/fs-tracer/src/syscall_handler.rs index c393bae..a9fda97 100644 --- a/fs-tracer/src/syscall_handler.rs +++ b/fs-tracer/src/syscall_handler.rs @@ -3,15 +3,17 @@ use std::ffi::CStr; use crossbeam_channel::Sender; use delay_map::HashMapDelay; -use fs_tracer_common::{OpenSyscallBPF, SyscallInfo, WriteSyscallBPF}; +use fs_tracer_common::{CloseSyscallBPF, OpenSyscallBPF, SyscallInfo, WriteSyscallBPF}; + +use crate::FSTracerFile; pub struct SyscallHandler { - resolved_files: Sender<String>, + resolved_files: Sender<FSTracerFile>, open_files: HashMapDelay<(i32, u32), String>, } impl SyscallHandler { - pub fn new(resolved_files: Sender<String>) -> Self { + pub fn new(resolved_files: Sender<FSTracerFile>) -> Self { Self { resolved_files, open_files: HashMapDelay::new(std::time::Duration::from_secs(400)), @@ -22,7 +24,7 @@ impl SyscallHandler { match data { SyscallInfo::Write(write_syscall) => self.handle_write(write_syscall), SyscallInfo::Open(open_syscall) => self.handle_open(open_syscall), - //TODO: SyscallInfo::Close + SyscallInfo::Close(close_syscall) => self.handle_close(close_syscall), } } @@ -45,20 +47,11 @@ impl SyscallHandler { "WRITE KERNEL: DATA {:?} FILENAME: {:?}", write_syscall, filename ); - let serialized_filename = serde_json::to_string(&filename).unwrap(); - let serialized_contents = serde_json::to_string(&contents).unwrap(); - let _ = self.resolved_files.send(format!( - r#" - {{ - "timestamp": "{}", - "absolute_path": {}, - "contents": {} - }} - "#, - chrono::Utc::now().to_rfc3339(), - serialized_filename, - serialized_contents, - )); + let _ = self.resolved_files.send(FSTracerFile { + timestamp: chrono::Utc::now().to_rfc3339(), + absolute_path: filename.to_string(), + contents: contents.to_string(), + }); Ok(()) } @@ -74,4 +67,25 @@ impl SyscallHandler { .insert((fd, open_syscall.pid), filename.to_string()); Ok(()) } + + fn handle_close(&mut self, close_syscall: CloseSyscallBPF) -> Result<(), ()> { + let filename = match self + .open_files + .remove(&(close_syscall.fd, close_syscall.pid)) + { + None => { + println!( + "DIDNT FIND AN OPEN FILE FOR THE CLOSE SYSCALL (fd: {})", + close_syscall.fd + ); + return Ok(()); + } + Some(str) => str, + }; + println!("CLOSE KERNEL DATA: {:?}", close_syscall); + println!("CLOSE FILENAME: {:?}", filename); + self.open_files + .remove(&(close_syscall.fd, close_syscall.pid)); + Ok(()) + } } diff --git a/tests/a.out b/tests/a.out index f601367..a6e5bdd 100755 --- a/tests/a.out +++ b/tests/a.out Binary files differdiff --git a/tests/openat.c b/tests/openat.c index 62628cc..d843d2f 100644 --- a/tests/openat.c +++ b/tests/openat.c @@ -8,19 +8,26 @@ int main(int argc, char** argv) { printf("PID: %d\n", getpid()); - int ret = syscall(SYS_openat, -100, "testfile", O_RDWR); - printf("Openat ret: %d\n", ret); + int fd = syscall(SYS_openat, -100, "testfile", O_RDWR); + printf("Openat ret: %d\n", fd); - if (ret == -1) { + if (fd == -1) { printf("Opneat error: %s\n", strerror(errno)); } - ret = syscall(SYS_write, ret, "writing this :)", 14); + int ret = syscall(SYS_write, fd, "I'm writing this :) pls.", 24); printf("Write ret: %d\n", ret); if (ret == -1) { printf("Write error: %s\n", strerror(errno)); } + + ret = syscall(SYS_close, fd); + printf("Close ret: %d\n", ret); + + if (ret == -1) { + printf("Close error: %s\n", strerror(errno)); + } return 0; } diff --git a/tests/testfile b/tests/testfile index f4ce76f..6426eb5 100644 --- a/tests/testfile +++ b/tests/testfile @@ -1,4 +1 @@ -writing this :t file - - -I have multiple lines :) +I'm writing this :) pls. \ No newline at end of file |