about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBaitinq <manuelpalenzuelamerino@gmail.com>2024-01-14 19:32:22 +0100
committerBaitinq <manuelpalenzuelamerino@gmail.com>2024-01-14 19:32:22 +0100
commit7bab8b108c1e2c238f9e5745ebdc2860a7cc5fcf (patch)
treea4252a8a019d1392cc2959b024248edf34ff24a2
parentHandle write syscall (diff)
downloadfs-tracer-7bab8b108c1e2c238f9e5745ebdc2860a7cc5fcf.tar.gz
fs-tracer-7bab8b108c1e2c238f9e5745ebdc2860a7cc5fcf.tar.bz2
fs-tracer-7bab8b108c1e2c238f9e5745ebdc2860a7cc5fcf.zip
Send write_syscall events to userspace
-rw-r--r--fs-tracer-common/src/lib.rs25
-rw-r--r--fs-tracer-ebpf/src/main.rs66
-rw-r--r--fs-tracer/Cargo.toml1
-rw-r--r--fs-tracer/src/main.rs37
4 files changed, 109 insertions, 20 deletions
diff --git a/fs-tracer-common/src/lib.rs b/fs-tracer-common/src/lib.rs
index 0c9ac1a..b8fcb1a 100644
--- a/fs-tracer-common/src/lib.rs
+++ b/fs-tracer-common/src/lib.rs
@@ -1 +1,26 @@
 #![no_std]
+
+use core::fmt::{Formatter, self};
+use core::str;
+
+
+#[derive(Clone, Copy)]
+pub struct WriteSyscallBPF {
+    pub pid: u32,
+    pub fd: u64,
+    pub buf: [u8; 128],
+    pub count: u64,
+}
+
+unsafe impl Sync for WriteSyscallBPF {}
+
+impl fmt::Debug for WriteSyscallBPF {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        f.debug_struct("WriteSyscallArgs")
+            .field("pid", &self.pid)
+            .field("fd", &self.fd)
+            .field("buf", &unsafe { str::from_utf8_unchecked(&self.buf) })
+            .field("count", &self.count)
+            .finish()
+    }
+}
\ No newline at end of file
diff --git a/fs-tracer-ebpf/src/main.rs b/fs-tracer-ebpf/src/main.rs
index 36365d8..b14154d 100644
--- a/fs-tracer-ebpf/src/main.rs
+++ b/fs-tracer-ebpf/src/main.rs
@@ -5,10 +5,24 @@ use core::ffi::c_void;
 use core::str;
 
 use aya_bpf::{
-    macros::tracepoint,
-    programs::TracePointContext, BpfContext, helpers::gen
+    macros::{tracepoint, map},
+    programs::TracePointContext, BpfContext, helpers::{gen::{self, bpf_probe_read_kernel_str}, bpf_probe_read_kernel_str_bytes}, maps::{PerfEventArray, PerCpuArray},
 };
 use aya_log_ebpf::info;
+use fs_tracer_common::WriteSyscallBPF;
+
+#[derive(Clone, Copy)]
+ struct WriteSyscallArgs {
+     fd: u64,
+     buf: *const u8,
+     count: u64,
+}
+
+#[map]
+static EVENTS: PerfEventArray<WriteSyscallBPF> = PerfEventArray::with_max_entries(1024, 0);
+
+//#[map]
+//static mut READ_FROM_USERSPACE_BUFFER: PerCpuArray<[u8;2048]> = PerCpuArray::with_max_entries(1, 0);
 
 #[tracepoint]
 pub fn fs_tracer(ctx: TracePointContext) -> u32 {
@@ -55,27 +69,47 @@ fn handle_syscall(ctx: TracePointContext, syscall_nr: i32) -> Result<u32, u32> {
     }
 }
 
-#[derive(Clone, Copy)]
-struct WriteArgs {
-    fd: u64,
-    buf: *const u8,
-    count: u64,
-}
+/*static mut read_from_userspace_buffer: [u8; 2048] = [0u8; 2048];
+static mut write_to_userspace_buffer: [u8; 2048] = [0u8; 2048];
+static mut write_syscall_bpf: WriteSyscallBPF = WriteSyscallBPF {
+    fd: 0,
+    buf: [0u8; 2048],
+    count: 0,
+};*/
 
 fn handle_sys_write(ctx: TracePointContext) -> Result<u32, u32> {
-    info!(&ctx, "handle_sys_write start");
-    let args = unsafe { *ptr_at::<WriteArgs>(&ctx, 16).unwrap() };
+    //info!(&ctx, "handle_sys_write start");
+    let args = unsafe { *ptr_at::<WriteSyscallArgs>(&ctx, 16).unwrap() };
 
-    info!(&ctx, "argfs fd: {}", args.fd);
-    let mut buf = [0u8; 256];
+    // if fd is stdout, stderr or stdin, ignore
+    if args.fd <= 2 {
+        return Ok(0)
+    }
+
+   // info!(&ctx, "argfs fd: {}", args.fd);
+    let mut buf = [0u8; 128];
+    //get_string_from_userspace(args.buf, unsafe { &mut *READ_FROM_USERSPACE_BUFFER.get_ptr_mut(0).unwrap() });
     get_string_from_userspace(args.buf, &mut buf);
     let buf_ref = &buf;
-    info!(&ctx, "buf: {}", unsafe { str::from_utf8_unchecked(buf_ref) });
-    info!(&ctx, "count: {}", args.count);
+   // info!(&ctx, "buf: {}", unsafe { str::from_utf8_unchecked(buf_ref) });
+    //info!(&ctx, "count: {}", args.count);                                                                                                               ";
+
+    let mut anotherbuf = [0u8; 128];
+    unsafe { bpf_probe_read_kernel_str(anotherbuf.as_mut_ptr() as *mut c_void, 128, buf_ref.as_ptr() as *const c_void) };
 
-    info!(&ctx, "handle_sys_write end");
+    EVENTS.output(&ctx, &WriteSyscallBPF {
+        pid: ctx.pid(),
+        fd: args.fd,
+        buf: anotherbuf,
+        count: args.count,
+    }, 0);
+
+    //info!(&ctx, "handle_sys_write end");
     return Ok(0)
-} //TODO: Communicate with userspace (share a some data structure in memory?)
+}
+
+//TODO: How are we going to correlate. We have open of a filename, we need to insert that into (pid, fd) -> filename. on close we remove from map. we need some timeout to remove stale entries
+//TODO: to get the fd from open, we need to know the return value of the syscall. for that we need a tracepoint on end and keep a map of (tgid, pid) -> WriteSyscallBPF)
 
 fn get_string_from_userspace(ptr: *const u8, buf: &mut [u8]) {
     unsafe { gen::bpf_probe_read_user_str( buf.as_mut_ptr() as *mut c_void, buf.len() as u32, ptr as *const c_void) };
diff --git a/fs-tracer/Cargo.toml b/fs-tracer/Cargo.toml
index 03ca947..ea9021d 100644
--- a/fs-tracer/Cargo.toml
+++ b/fs-tracer/Cargo.toml
@@ -12,6 +12,7 @@ anyhow = "1"
 env_logger = "0.10"
 libc = "0.2"
 log = "0.4"
+bytes = "1.5.0"
 tokio = { version = "1.25", features = ["macros", "rt", "rt-multi-thread", "net", "signal"] }
 
 [[bin]]
diff --git a/fs-tracer/src/main.rs b/fs-tracer/src/main.rs
index 721c893..25edeb7 100644
--- a/fs-tracer/src/main.rs
+++ b/fs-tracer/src/main.rs
@@ -1,8 +1,14 @@
+use std::fmt::Write;
+
+use aya::maps::AsyncPerfEventArray;
 use aya::programs::TracePoint;
+use aya::util::online_cpus;
 use aya::{include_bytes_aligned, Bpf};
 use aya_log::BpfLogger;
 use log::{info, warn, debug};
-use tokio::signal;
+use tokio::{signal, task};
+use bytes::BytesMut;
+use fs_tracer_common::WriteSyscallBPF;
 
 #[tokio::main]
 async fn main() -> Result<(), anyhow::Error> {
@@ -37,10 +43,33 @@ async fn main() -> Result<(), anyhow::Error> {
     }
     let program: &mut TracePoint = bpf.program_mut("fs_tracer").unwrap().try_into()?;
     program.load()?;
-    program.attach("syscalls", "sys_enter_open")?;
+    //program.attach("syscalls", "sys_enter_open")?;
     program.attach("syscalls", "sys_enter_write")?;
-    program.attach("syscalls", "sys_enter_lseek")?;
-    program.attach("syscalls", "sys_enter_close")?;
+    //program.attach("syscalls", "sys_enter_lseek")?;
+    //program.attach("syscalls", "sys_enter_close")?;
+
+    println!("Num of cpus: {}", online_cpus()?.len());
+
+    let mut perf_array =
+        AsyncPerfEventArray::try_from(bpf.take_map("EVENTS").unwrap())?;
+        for cpu_id in online_cpus()? {
+            let mut buf = perf_array.open(cpu_id, None)?;
+    
+            task::spawn(async move {
+                let mut buffers = (0..10)
+                    .map(|_| BytesMut::with_capacity(1024))
+                    .collect::<Vec<_>>();
+    
+                loop {
+                    let events = buf.read_events(&mut buffers).await.unwrap();
+                    for buf in buffers.iter_mut().take(events.read) {
+                        let ptr = buf.as_ptr() as *const WriteSyscallBPF;
+                        let data = unsafe { ptr.read_unaligned() };
+                        println!("KERNEL: DATA {:?}", data);
+                    }
+                }
+            });
+        }
 
     info!("Waiting for Ctrl-C...");
     signal::ctrl_c().await?;