about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBaitinq <[email protected]>2024-07-22 22:43:00 +0200
committerBaitinq <[email protected]>2024-07-22 22:43:00 +0200
commitd9ad9d226fd4613509c73b99e13f11606c10ff0d (patch)
tree54e25ba99e915e0905d272ad5e293958a38fc7db
parentfs-tracer: open files should be referenced with pid+fd (diff)
downloadfs-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--TODO1
-rw-r--r--fs-tracer-common/src/lib.rs21
-rw-r--r--fs-tracer-ebpf/src/main.rs5
-rw-r--r--fs-tracer-ebpf/src/syscalls/close.rs57
-rw-r--r--fs-tracer-ebpf/src/syscalls/mod.rs2
-rw-r--r--fs-tracer-ebpf/src/syscalls/write.rs2
-rw-r--r--fs-tracer/src/main.rs44
-rw-r--r--fs-tracer/src/syscall_handler.rs50
-rwxr-xr-xtests/a.outbin15872 -> 15872 bytes
-rw-r--r--tests/openat.c15
-rw-r--r--tests/testfile5
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