diff --git a/src/bpf/hs_trace.bpf.c b/src/bpf/hs_trace.bpf.c index c5ccb0a..5b9670f 100644 --- a/src/bpf/hs_trace.bpf.c +++ b/src/bpf/hs_trace.bpf.c @@ -20,6 +20,13 @@ struct { __uint(max_entries, 1); } missed_events SEC(".maps"); +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __type(key, u32); + __type(value, u64); + __uint(max_entries, 1024 * 1024); +} pipe_tracker SEC(".maps"); + // struct { // __uint(type, BPF_MAP_TYPE_HASH); // __type(key, struct unique_file_t); @@ -48,6 +55,146 @@ enum syscall_event_type { SYS_EXIT }; +struct sys_enter_pipe2_args { + unsigned short common_type; + unsigned char common_flags; + unsigned char common_preempt_count; + int common_pid; + int id; // syscall number + int *fildes; // pipe fds + long flags; // flags +}; + +SEC("tracepoint/syscalls/sys_enter_pipe2") + +int +BPF_PROG(hs_trace_create_pipe) +{ + u64 pid_tgid = bpf_get_current_pid_tgid(); + u32 pid = pid_tgid & 0xFFFFFFFF; + + if (bpf_map_lookup_elem(&pid_set, &pid) == NULL) { + return 0; + } + + u64 ptr = (u64)((struct sys_enter_pipe2_args *)ctx)->fildes; + if (bpf_map_update_elem(&pipe_tracker, &pid, &ptr, BPF_ANY) < 0) { + bpf_printk("failed to update pipe_tracker with pid %d\n", pid); + return 0; + } + + return 0; +} + +struct sys_exit_pipe2_args { + unsigned short common_type; + unsigned char common_flags; + unsigned char common_preempt_count; + int common_pid; + int id; // syscall number + long ret; // return value +}; + +SEC("tracepoint/syscalls/sys_exit_pipe2") + +int +BPF_PROG(hs_trace_create_pipe_exit) +{ + struct sys_enter_info2_t *enter2; + + u64 pid_tgid = bpf_get_current_pid_tgid(); + u32 pid = pid_tgid & 0xFFFFFFFF; + if (bpf_map_lookup_elem(&pid_set, &pid) == NULL) { + // bpf_printk("pid %d is not in set\n", pid); + return 0; + } + if (((struct sys_exit_pipe2_args *)ctx)->ret < 0) { + return 0; + } + + u64 *fds_pointers; + if ((fds_pointers = bpf_map_lookup_elem(&pipe_tracker, &pid)) == NULL) { + return 0; + } + + if ((enter2 = bpf_ringbuf_reserve( + &output, sizeof(struct sys_enter_info2_t), 0)) == NULL) { + // bpf_printk("FAILED to reserve space in ring buffer + // for " + // "event_type == " + // "SYS_ENTER2\n"); + u32 key = 0; + u32 *missed = bpf_map_lookup_elem(&missed_events, &key); + if (missed) { + __sync_fetch_and_add(missed, 1); + } + + return 0; + } + + enter2->pid_tgid = pid_tgid; + enter2->syscall_nr = ((struct sys_exit_pipe2_args *)ctx)->id; + enter2->flags = -1; + bpf_map_delete_elem(&pipe_tracker, &pid); + + + + int fds[2]; + bpf_probe_read_user(&fds, sizeof(fds), (void *)(*fds_pointers)); + enter2->fd = fds[0]; + enter2->fd2 = fds[1]; + + // bpf_rcu_read_lock(); + + struct task_struct *t = (void *)bpf_get_current_task_btf(); + struct files_struct *files = BPF_CORE_READ(t, files); + struct fdtable *fdtp = NULL; + + bpf_probe_read_kernel(&fdtp, sizeof(fdtp), &files->fdt); + + struct file **fd_array = NULL; + bpf_probe_read_kernel(&fd_array, sizeof(fd_array), &fdtp->fd); + + + int fd0 = fds[0]; + struct file *file0 = NULL; + bpf_probe_read_kernel(&file0, sizeof(file0), &fd_array[fd0]); + + + u64 ino = 0; + ino = BPF_CORE_READ(file0, f_inode, i_ino); + // bpf_rcu_read_unlock(); + + char *path2 = NULL; + char pipe_str[32]; + BPF_SNPRINTF(enter2->path, sizeof(pipe_str), "/pipe:[%d]", ino); + + bpf_probe_read_user_str(&enter2->path2, sizeof(enter2->path2), path2); + + bpf_ringbuf_submit(enter2, 0); + + struct sys_exit_info_t *exit; + if ((exit = bpf_ringbuf_reserve(&output, sizeof(struct sys_exit_info_t), + 0)) == NULL) { + // bpf_printk( + // "FAILED to reserve space in ring buffer for event_type == + // " "SYS_EXIT\n"); + u32 key = 0; + u32 *missed = bpf_map_lookup_elem(&missed_events, &key); + if (missed) { + __sync_fetch_and_add(missed, 1); + } + + return 0; + } + exit->pid_tgid = pid_tgid; + exit->ret = ((struct sys_exit_pipe2_args *)ctx)->ret; + bpf_ringbuf_submit(exit, 0); + + return 0; +} + + SEC("tp_btf/sched_process_fork") int @@ -85,7 +232,7 @@ BPF_PROG(hs_trace_process_fork, struct task_struct *parent, } return 0; } - enter0->pid = p_pid_tgid; + enter0->pid_tgid = p_pid_tgid; enter0->syscall_nr = __NR_clone; enter0->flags = 0; bpf_ringbuf_submit(enter0, 0); @@ -104,7 +251,7 @@ BPF_PROG(hs_trace_process_fork, struct task_struct *parent, return 0; } - exit->pid = p_pid_tgid; + exit->pid_tgid = p_pid_tgid; exit->ret = c_pid_tgid; bpf_ringbuf_submit(exit, 0); return 0; @@ -152,6 +299,14 @@ BPF_PROG(hs_trace_sys_enter, struct pt_regs *regs, long syscall_id) event_type = SYS_ENTER1; break; #endif +#ifdef __NR_openat2 + case __NR_openat2: /* individually */ + fd = (int)PT_REGS_PARM1_CORE(regs); + path = (char *)PT_REGS_PARM2_CORE(regs); + flags = (int)PT_REGS_PARM3_CORE(regs); + event_type = SYS_ENTER1; + break; +#endif #ifdef __NR_open case __NR_open: path = (char *)PT_REGS_PARM1_CORE(regs); @@ -217,6 +372,22 @@ BPF_PROG(hs_trace_sys_enter, struct pt_regs *regs, long syscall_id) event_type = SYS_ENTER1; break; #endif +#ifdef __NR_dup2 + case __NR_dup2: +#endif +#ifdef __NR_dup3 + case __NR_dup3: + fd = (int)PT_REGS_PARM1_CORE(regs); + fd2 = (int)PT_REGS_PARM2_CORE(regs); + event_type = SYS_ENTER2; + break; +#endif +#ifdef __NR_dup + case __NR_dup: + fd = (int)PT_REGS_PARM1_CORE(regs); + event_type = SYS_ENTER1; + break; +#endif #ifdef __NR_execve case __NR_execve: /* r_first_path_set */ #endif @@ -363,7 +534,7 @@ BPF_PROG(hs_trace_sys_enter, struct pt_regs *regs, long syscall_id) return 0; } - enter0->pid = pid_tgid; + enter0->pid_tgid = pid_tgid; enter0->syscall_nr = syscall_id; enter0->flags = flags; bpf_ringbuf_submit(enter0, 0); @@ -383,7 +554,7 @@ BPF_PROG(hs_trace_sys_enter, struct pt_regs *regs, long syscall_id) return 0; } - enter1->pid = pid_tgid; + enter1->pid_tgid = pid_tgid; enter1->syscall_nr = syscall_id; enter1->flags = flags; enter1->fd = fd; @@ -406,7 +577,7 @@ BPF_PROG(hs_trace_sys_enter, struct pt_regs *regs, long syscall_id) return 0; } - enter2->pid = pid_tgid; + enter2->pid_tgid = pid_tgid; enter2->syscall_nr = syscall_id; enter2->flags = flags; enter2->fd = fd; @@ -448,6 +619,9 @@ BPF_PROG(hs_trace_sys_exit) #ifdef __NR_openat case __NR_openat: /* individually */ #endif +#ifdef __NR_openat2 + case __NR_openat2: /* individually */ +#endif #ifdef __NR_open case __NR_open: #endif @@ -478,6 +652,14 @@ BPF_PROG(hs_trace_sys_exit) #ifdef __NR_execve case __NR_execve: /* r_first_path_set */ #endif +#ifdef __NR_dup2 + case __NR_dup2: +#endif +#ifdef __NR_dup3 + case __NR_dup3: +#endif +#ifdef __NR_dup +#endif #ifdef __NR_statfs case __NR_statfs: #endif @@ -601,7 +783,7 @@ BPF_PROG(hs_trace_sys_exit) return 0; } - exit->pid = pid_tgid; + exit->pid_tgid = pid_tgid; exit->ret = ((struct sys_exit_args *)ctx)->ret; bpf_ringbuf_submit(exit, 0); diff --git a/src/bpf/hs_trace.h b/src/bpf/hs_trace.h index 2edca37..5bf6161 100644 --- a/src/bpf/hs_trace.h +++ b/src/bpf/hs_trace.h @@ -7,31 +7,31 @@ struct unique_file_t { }; struct sys_enter_info0_t { - long int pid; + long int pid_tgid; long int syscall_nr; int flags; // for special handling: open*, clone, linkat, etc. }; struct sys_enter_info1_t { - long int pid; + long int pid_tgid; long int syscall_nr; int flags; // for special handling: open*, clone, linkat, etc. - int fd; // for -at syscalls: could be AT_FDCWD + int fd; // for -at syscalls: could be AT_FDCWD char path[4096]; }; struct sys_enter_info2_t { - long int pid; + long int pid_tgid; long int syscall_nr; int flags; // for special handling: open*, clone, linkat, etc. - int fd; // for -at syscalls: could be AT_FDCWD - int fd2; // for renameat2 and linkat + int fd; // for -at syscalls: could be AT_FDCWD + int fd2; // for renameat2 and linkat char path[4096]; char path2[4096]; }; struct sys_exit_info_t { - long int pid; + long int pid_tgid; long int ret; }; diff --git a/src/dep_tracer.rs b/src/dep_tracer.rs index d81679b..ee3013d 100644 --- a/src/dep_tracer.rs +++ b/src/dep_tracer.rs @@ -7,6 +7,7 @@ use std::path::{Component, PathBuf}; use std::sync::mpsc; use std::sync::{Mutex, RwLock}; use trace_v3::*; + #[cfg(target_arch = "x86_64")] pub fn individually_handled_syscall_map() -> HashMap { let mut m = HashMap::new(); @@ -168,12 +169,16 @@ impl Logs { } pub fn dump_log(&mut self) { - for (pid_tgid, log) in self.log.iter() { - println!( - "log for pid {} tgid {}:", - pid_tgid & 0xFFFFFFFF, - pid_tgid >> 32 - ); + let mut sorted_logs: Vec<_> = self + .log + .iter() + .map(|(pid_tgid, logs)| (pid_tgid & 0xFFFFFFFF, pid_tgid >> 32, logs)) + .collect(); + + sorted_logs.sort_by(|(pid1, _, _), (pid2, _, _)| pid1.cmp(pid2)); + + for (pid, tgid, log) in sorted_logs { + println!("log for pid {} tgid {}:", pid, tgid); for e in log.iter() { match e { SyscallEvent::Enter0(e) => { @@ -215,6 +220,7 @@ pub struct Context { cwd_map: HashMap, process_graph: HashMap, dirfd_map: HashMap<(u64, i32), PathBuf>, + openfds_map: HashMap<(i32, i32), PathBuf>, } impl Context { @@ -223,6 +229,7 @@ impl Context { cwd_map: HashMap::new(), process_graph: HashMap::new(), dirfd_map: HashMap::new(), + openfds_map: HashMap::new(), } } pub fn init_pid(&mut self, pid: u64, cwd: PathBuf) { @@ -233,6 +240,23 @@ impl Context { self.process_graph.insert(child_pid_tgid, parent_pid_tgid); let parent_cwd = self.cwd_map.get(&parent_pid_tgid).unwrap(); self.cwd_map.insert(child_pid_tgid, parent_cwd.clone()); + let new_pid_fds: Vec<_> = self + .openfds_map + .iter() + .filter(|((pid, _), _)| *pid == (parent_pid_tgid & 0xFFFFFFFF) as i32) + .map(|(&key, path)| (key, path.clone())) + .collect(); + for ((_old_pid, fd), path) in new_pid_fds { + self.map_fds((child_pid_tgid & 0xFFFFFFFF) as i32, fd, path.to_owned()) + } + } + + pub fn map_fds(&mut self, pid: i32, fd: i32, path: PathBuf) { + self.openfds_map.insert((pid, fd), path); + } + + pub fn get_path_from_fd(&self, pid: i32, fd: i32) -> Option { + self.openfds_map.get(&(pid, fd)).map(|path| path.clone()) } } @@ -287,15 +311,16 @@ impl RWSet { pub static CTXT: Lazy> = Lazy::new(|| Mutex::new(Context::new())); pub static SETS: Lazy> = Lazy::new(|| Mutex::new(RWSet::new())); pub static LOGS: Lazy> = Lazy::new(|| Mutex::new(Logs::new())); + enum SyscallInfo { Event0 { - pid: u64, + pid_tgid: u64, ret: i64, syscall_nr: i64, flags: u32, }, Event1 { - pid: u64, + pid_tgid: u64, ret: i64, syscall_nr: i64, flags: u32, @@ -303,7 +328,7 @@ enum SyscallInfo { path: String, }, Event2 { - pid: u64, + pid_tgid: u64, ret: i64, syscall_nr: i64, flags: u32, @@ -319,54 +344,60 @@ fn on_event_update_rw_sets(event: SyscallInfo) { let mut sets = SETS.lock().unwrap(); match event { SyscallInfo::Event0 { - pid, + pid_tgid, ret, syscall_nr, flags, } => match syscall_nr { - libc::SYS_clone => parse_clone(&mut ctxt, &mut sets, pid, ret, syscall_nr, flags), + libc::SYS_clone => parse_clone(&mut ctxt, &mut sets, pid_tgid, ret, syscall_nr, flags), _ => {} }, SyscallInfo::Event1 { - pid, + pid_tgid, ret, syscall_nr, flags, fd, path, } => match syscall_nr { + libc::SYS_dup => parse_dup( + &mut ctxt, &mut sets, pid_tgid, ret, syscall_nr, flags, fd, &path, + ), libc::SYS_inotify_add_watch => parse_SYS_inotify_add_watch( - &mut ctxt, &mut sets, pid, ret, syscall_nr, flags, fd, &path, + &mut ctxt, &mut sets, pid_tgid, ret, syscall_nr, flags, fd, &path, + ), + libc::SYS_openat | libc::SYS_openat2 => parse_openat( + &mut ctxt, &mut sets, pid_tgid, ret, syscall_nr, flags, fd, &path, ), - libc::SYS_openat => { - parse_openat(&mut ctxt, &mut sets, pid, ret, syscall_nr, flags, fd, &path) - } - // #[cfg(target_arch = "x86_64")] // libc::SYS_open => { // let mut ctxt = CTXT.lock().unwrap(); // let mut sets = SETS.lock().unwrap(); - // parse_open(&mut ctxt, &mut sets, pid, ret, syscall_nr, flags, fd, &path) + // parse_open( + // &mut ctxt, &mut sets, pid_tgid, ret, syscall_nr, flags, fd, &path, + // ) // } - libc::SYS_chdir => { - parse_chdir(&mut ctxt, &mut sets, pid, ret, syscall_nr, flags, fd, &path) - } - libc::SYS_symlinkat => { - parse_symlinkat(&mut ctxt, &mut sets, pid, ret, syscall_nr, flags, fd, &path) - } + libc::SYS_chdir => parse_chdir( + &mut ctxt, &mut sets, pid_tgid, ret, syscall_nr, flags, fd, &path, + ), + libc::SYS_symlinkat => parse_symlinkat( + &mut ctxt, &mut sets, pid_tgid, ret, syscall_nr, flags, fd, &path, + ), // libc::SYS_symlink => {} // r path libc::SYS_execve | libc::SYS_statfs | libc::SYS_getxattr | libc::SYS_lgetxattr => { - parse_r_first_path_e1(&mut ctxt, &mut sets, pid, ret, syscall_nr, flags, fd, &path) + parse_r_first_path_e1( + &mut ctxt, &mut sets, pid_tgid, ret, syscall_nr, flags, fd, &path, + ) } // libc::SYS_stat => {} // libc::SYS_lstat => {} // libc::SYS_access => {} // libc::SYS_readlink => {} // w path - libc::SYS_truncate | libc::SYS_acct => { - parse_w_first_path_e1(&mut ctxt, &mut sets, pid, ret, syscall_nr, flags, fd, &path) - } + libc::SYS_truncate | libc::SYS_acct => parse_w_first_path_e1( + &mut ctxt, &mut sets, pid_tgid, ret, syscall_nr, flags, fd, &path, + ), // libc::SYS_mkdir => {} // libc::SYS_rmdir => {} // libc::SYS_creat => {} @@ -384,9 +415,9 @@ fn on_event_update_rw_sets(event: SyscallInfo) { | libc::SYS_readlinkat | libc::SYS_faccessat | libc::SYS_faccessat2 - | libc::SYS_execveat => { - parse_r_fd_path_e1(&mut ctxt, &mut sets, pid, ret, syscall_nr, flags, fd, &path) - } + | libc::SYS_execveat => parse_r_fd_path_e1( + &mut ctxt, &mut sets, pid_tgid, ret, syscall_nr, flags, fd, &path, + ), // w fd path libc::SYS_linkat | libc::SYS_unlinkat @@ -394,14 +425,14 @@ fn on_event_update_rw_sets(event: SyscallInfo) { | libc::SYS_mkdirat | libc::SYS_mknodat | libc::SYS_fchownat - | libc::SYS_fchmodat => { - parse_r_fd_path_e1(&mut ctxt, &mut sets, pid, ret, syscall_nr, flags, fd, &path) - } + | libc::SYS_fchmodat => parse_w_fd_path_e1( + &mut ctxt, &mut sets, pid_tgid, ret, syscall_nr, flags, fd, &path, + ), // libc::SYS_futimeat => {} _ => {} }, SyscallInfo::Event2 { - pid, + pid_tgid, ret, syscall_nr, flags, @@ -410,37 +441,47 @@ fn on_event_update_rw_sets(event: SyscallInfo) { fd2, path2, } => match syscall_nr { + libc::SYS_dup3 => parse_dup23( + &mut ctxt, &mut sets, pid_tgid, ret, syscall_nr, flags, fd, &path, fd2, &path2, + ), // libc::SYS_link => {} // libc::SYS_rename => {} libc::SYS_renameat | libc::SYS_renameat2 => parse_renameat( - &mut ctxt, &mut sets, pid, ret, syscall_nr, flags, fd, &path, fd2, &path2, + &mut ctxt, &mut sets, pid_tgid, ret, syscall_nr, flags, fd, &path, fd2, &path2, + ), + libc::SYS_pipe2 => parse_pipe2( + &mut ctxt, &mut sets, pid_tgid, ret, syscall_nr, flags, fd, &path, fd2, &path2, ), _ => {} }, } } + fn is_absolute_path(path: &str) -> bool { !path.is_empty() && path.starts_with('/') } -fn convert_absolute(ctxt: &Context, pid: u64, raw_path: &str, dirfd: Option) -> PathBuf { +fn convert_absolute(ctxt: &Context, pid_tgid: u64, raw_path: &str, dirfd: Option) -> PathBuf { let binding = if is_absolute_path(raw_path) { PathBuf::from(raw_path) } else { let base = if let Some(fd) = dirfd { if fd == libc::AT_FDCWD { ctxt.cwd_map - .get(&pid) - .expect("pid not found bc pid not in cwd") + .get(&pid_tgid) + .expect("pid_tgid not found bc pid_tgid not in cwd") .clone() } else { ctxt.dirfd_map - .get(&(pid, fd)) - .expect("fd or pid not found in map") + .get(&(pid_tgid, fd)) + .expect("fd or pid_tgid not found in map") .clone() } } else { - ctxt.cwd_map.get(&pid).expect("pid not found").clone() + ctxt.cwd_map + .get(&pid_tgid) + .expect("pid_tgid not found") + .clone() }; base.join(raw_path) }; @@ -475,10 +516,82 @@ enum AccessKind { Write, } +fn parse_dup( + ctxt: &mut Context, + _sets: &mut RWSet, + pid_tgid: u64, + ret: i64, + _syscall_nr: i64, + _flags: u32, + fd: i32, + _path: &str, +) { + if ret < 0 { + return; + } + + let new_fd = match i32::try_from(ret) { + Ok(x) => x, + Err(_) => return, + }; + + let pid: i32 = (pid_tgid & 0xFFFF_FFFF) as i32; + + if let Some(p) = ctxt.get_path_from_fd(pid, fd) { + ctxt.map_fds(pid, fd, p.clone()); + ctxt.map_fds(pid, new_fd, p); + } +} + +fn parse_dup23( + ctxt: &mut Context, + sets: &mut RWSet, + pid_tgid: u64, + ret: i64, + syscall_nr: i64, + flags: u32, + fd: i32, + path: &str, + fd2: i32, + path2: &str, +) { + let pid = (pid_tgid & 0xFFFFFFFF) as i32; + + if ret >= 0 { + let new_map = ctxt.get_path_from_fd(pid, fd); + if let Some(valid_path) = new_map { + ctxt.map_fds(pid, fd2, valid_path); + } + } +} + +fn parse_pipe2( + ctxt: &mut Context, + sets: &mut RWSet, + pid_tgid: u64, + ret: i64, + syscall_nr: i64, + flags: u32, + fd: i32, + path: &str, + fd2: i32, + path2: &str, +) { + let path = convert_absolute(ctxt, pid_tgid, path, None); + let pid = (pid_tgid & 0xFFFFFFFF) as i32; + println!("{pid}"); + + ctxt.map_fds(pid, fd, path.clone()); + ctxt.map_fds(pid, fd2, path.clone()); + insert_with_ancestors(sets, path.clone(), AccessKind::Read); + insert_with_ancestors(sets, path, AccessKind::Write); + +} + fn parse_SYS_inotify_add_watch( ctxt: &mut Context, sets: &mut RWSet, - pid: u64, + pid_tgid: u64, ret: i64, syscall_nr: i64, flags: u32, @@ -488,50 +601,101 @@ fn parse_SYS_inotify_add_watch( if path.is_empty() { return; } - let abs = convert_absolute(ctxt, pid, path, None); + let abs = convert_absolute(ctxt, pid_tgid, path, None); insert_with_ancestors(sets, abs, AccessKind::Read); } +// fn parse_openat( +// ctxt: &mut Context, +// sets: &mut RWSet, +// pid: u64, +// ret: i64, +// syscall_nr: i64, +// flags: u32, +// fd: i32, +// path: &str, +// ) { +// let abs = convert_absolute(&ctxt, pid, &path, Some(fd)); +// if ret >= 0 { +// let new_fd = ret as i32; +// ctxt.map_fds((pid & 0xFFFFFFFF) as i32, new_fd, abs.clone()); + +// if (flags & libc::O_DIRECTORY as u32) != 0 { +// ctxt.dirfd_map.insert((pid, new_fd), abs.clone()); +// } +// } + +// let kind = if ret < 0 { +// AccessKind::Read +// } else if (flags & libc::O_RDONLY as u32) != 0 { +// AccessKind::Read +// } else { +// AccessKind::Write +// }; +// insert_with_ancestors(sets, abs, kind); +// } + fn parse_openat( ctxt: &mut Context, sets: &mut RWSet, - pid: u64, + pid_tgid: u64, ret: i64, syscall_nr: i64, flags: u32, fd: i32, path: &str, ) { - let abs = convert_absolute(&ctxt, pid, &path, Some(fd)); + let abs = convert_absolute(&ctxt, pid_tgid, &path, Some(fd)); + if ret >= 0 { + let new_fd = ret as i32; + ctxt.map_fds((pid_tgid & 0xFFFFFFFF) as i32, new_fd, abs.clone()); - if ret >= 0 && (flags & libc::O_DIRECTORY as u32) != 0 { - ctxt.dirfd_map.insert((pid, ret as i32), abs.clone()); + if (flags & libc::O_DIRECTORY as u32) != 0 { + ctxt.dirfd_map.insert((pid_tgid, new_fd), abs.clone()); + } } - let kind = if ret < 0 { - AccessKind::Read - } else if (flags & libc::O_RDONLY as u32) != 0 { - AccessKind::Read + if ret < 0 { + // Failed open is always a read attempt + insert_with_ancestors(sets, abs, AccessKind::Read); } else { - AccessKind::Write - }; - insert_with_ancestors(sets, abs, kind); + // Check the access mode (lower 2 bits of flags) + let access_mode = (flags & libc::O_ACCMODE as u32) as i32; + + match access_mode { + libc::O_RDONLY => { + insert_with_ancestors(sets, abs, AccessKind::Read); + } + libc::O_WRONLY => { + insert_with_ancestors(sets, abs, AccessKind::Write); + } + libc::O_RDWR => { + // File is opened for both reading and writing + insert_with_ancestors(sets, abs.clone(), AccessKind::Read); + insert_with_ancestors(sets, abs, AccessKind::Write); + } + _ => { + // Shouldn't happen, but default to read + insert_with_ancestors(sets, abs, AccessKind::Read); + } + } + } } fn parse_open( ctxt: &mut Context, sets: &mut RWSet, - pid: u64, + pid_tgid: u64, ret: i64, syscall_nr: i64, flags: u32, fd: i32, path: &str, ) { - let abs = convert_absolute(&ctxt, pid, &path, None); + let abs = convert_absolute(&ctxt, pid_tgid, &path, None); if ret >= 0 && (flags & libc::O_DIRECTORY as u32) != 0 { - ctxt.dirfd_map.insert((pid, ret as i32), abs.clone()); + ctxt.dirfd_map.insert((pid_tgid, ret as i32), abs.clone()); } let kind = if ret < 0 { @@ -547,16 +711,16 @@ fn parse_open( fn parse_chdir( ctxt: &mut Context, sets: &mut RWSet, - pid: u64, + pid_tgid: u64, ret: i64, syscall_nr: i64, flags: u32, fd: i32, path: &str, ) { - let abs = convert_absolute(ctxt, pid, &path, None); + let abs = convert_absolute(ctxt, pid_tgid, &path, None); if ret == 0 { - ctxt.cwd_map.insert(pid, abs.clone()); + ctxt.cwd_map.insert(pid_tgid, abs.clone()); } insert_with_ancestors(sets, abs, AccessKind::Read); } @@ -564,7 +728,7 @@ fn parse_chdir( fn parse_clone( ctxt: &mut Context, sets: &mut RWSet, - pid: u64, + pid_tgid: u64, ret: i64, syscall_nr: i64, flags: u32, @@ -572,20 +736,22 @@ fn parse_clone( if ret < 0 { return; }; - ctxt.do_clone(pid, ret as u64) + let pid = (pid_tgid & 0xFFFFFFFF) as i32; + let r = ret as i32; + ctxt.do_clone(pid_tgid, ret as u64) } fn parse_symlinkat( ctxt: &mut Context, sets: &mut RWSet, - pid: u64, + pid_tgid: u64, ret: i64, syscall_nr: i64, flags: u32, fd: i32, path: &str, ) { - let abs = convert_absolute(ctxt, pid, &path, Some(fd)); + let abs = convert_absolute(ctxt, pid_tgid, &path, Some(fd)); let kind = if ret != 0 { AccessKind::Read } else { @@ -598,7 +764,7 @@ fn parse_symlinkat( fn parse_r_first_path_e1( ctxt: &mut Context, sets: &mut RWSet, - pid: u64, + pid_tgid: u64, ret: i64, syscall_nr: i64, flags: u32, @@ -608,7 +774,7 @@ fn parse_r_first_path_e1( if path.is_empty() { return; } - let abs = convert_absolute(ctxt, pid, &path, None); + let abs = convert_absolute(ctxt, pid_tgid, &path, None); insert_with_ancestors(sets, abs, AccessKind::Read); } @@ -616,7 +782,7 @@ fn parse_r_first_path_e1( fn parse_w_first_path_e1( ctxt: &mut Context, sets: &mut RWSet, - pid: u64, + pid_tgid: u64, ret: i64, syscall_nr: i64, flags: u32, @@ -627,7 +793,7 @@ fn parse_w_first_path_e1( return; } - let abs = convert_absolute(ctxt, pid, path, None); + let abs = convert_absolute(ctxt, pid_tgid, path, None); let kind = if ret == 0 { AccessKind::Write } else { @@ -640,7 +806,7 @@ fn parse_w_first_path_e1( fn parse_r_fd_path_e1( ctxt: &mut Context, sets: &mut RWSet, - pid: u64, + pid_tgid: u64, ret: i64, syscall_nr: i64, flags: u32, @@ -651,7 +817,7 @@ fn parse_r_fd_path_e1( return; } - let abs = convert_absolute(ctxt, pid, path, Some(fd)); + let abs = convert_absolute(ctxt, pid_tgid, path, Some(fd)); insert_with_ancestors(sets, abs, AccessKind::Read); } @@ -659,7 +825,7 @@ fn parse_r_fd_path_e1( fn parse_w_fd_path_e1( ctxt: &mut Context, sets: &mut RWSet, - pid: u64, + pid_tgid: u64, ret: i64, syscall_nr: i64, flags: u32, @@ -670,7 +836,7 @@ fn parse_w_fd_path_e1( return; } - let abs = convert_absolute(ctxt, pid, path, Some(fd)); + let abs = convert_absolute(ctxt, pid_tgid, path, Some(fd)); let kind = if ret != 0 { AccessKind::Read @@ -684,7 +850,7 @@ fn parse_w_fd_path_e1( fn parse_renameat( ctxt: &mut Context, sets: &mut RWSet, - pid: u64, + pid_tgid: u64, ret: i64, syscall_nr: i64, flags: u32, @@ -693,8 +859,8 @@ fn parse_renameat( fd2: i32, path2: &str, ) { - let abs_path_1 = convert_absolute(ctxt, pid, path, Some(fd)); - let abs_path_2 = convert_absolute(ctxt, pid, path2, Some(fd2)); + let abs_path_1 = convert_absolute(ctxt, pid_tgid, path, Some(fd)); + let abs_path_2 = convert_absolute(ctxt, pid_tgid, path2, Some(fd2)); insert_with_ancestors(sets, abs_path_1, AccessKind::Write); insert_with_ancestors(sets, abs_path_2, AccessKind::Write); @@ -721,32 +887,54 @@ pub fn event_stream_handler(rx: mpsc::Receiver>) -> Result< loop { match rx.recv() { Ok(Some(SyscallEvent::Enter0(e))) => { - let pid = e.pid as u64; + let pid_tgid = e.pid_tgid as u64; let mut logs = LOGS.lock().unwrap(); - logs.update_log(pid, SyscallEvent::Enter0(e)) + logs.update_log(pid_tgid, SyscallEvent::Enter0(e)) } - Ok(Some(SyscallEvent::Enter1(e))) => { - let pid = e.pid as u64; + Ok(Some(SyscallEvent::Enter1(mut e))) => { + let pid_tgid = e.pid_tgid as u64; + { + let ctxt = CTXT.lock().unwrap(); + if libc::SYS_dup == e.syscall_nr { + let pid = (e.pid_tgid & 0xFFFFFFFF) as i32; + if let Some(p) = ctxt.get_path_from_fd(pid, e.fd) { + let path = p.to_str().unwrap().as_bytes(); + let len = e.path.len().min(path.len()); + e.path[..len].copy_from_slice(path); + } + } + } let mut logs = LOGS.lock().unwrap(); - logs.update_log(pid, SyscallEvent::Enter1(e)) + logs.update_log(pid_tgid, SyscallEvent::Enter1(e)) } - Ok(Some(SyscallEvent::Enter2(e))) => { - let pid = e.pid as u64; + Ok(Some(SyscallEvent::Enter2(mut e))) => { + let pid_tgid = e.pid_tgid as u64; + { + let ctxt = CTXT.lock().unwrap(); + if libc::SYS_dup3 == e.syscall_nr { + let pid = (e.pid_tgid & 0xFFFFFFFF) as i32; + if let Some(p) = ctxt.get_path_from_fd(pid, e.fd) { + let path = p.to_str().unwrap().as_bytes(); + let len = e.path.len().min(path.len()); + e.path[..len].copy_from_slice(path); + } + } + } let mut logs = LOGS.lock().unwrap(); - logs.update_log(pid, SyscallEvent::Enter2(e)) + logs.update_log(pid_tgid, SyscallEvent::Enter2(e)) } Ok(Some(SyscallEvent::Exit(exit_info))) => { - let pid = exit_info.pid as u64; + let pid_tgid = exit_info.pid_tgid as u64; let mut logs = LOGS.lock().unwrap(); - logs.update_log(pid, SyscallEvent::Exit(exit_info)); - let event_queue = logs.log.get(&pid).unwrap(); + logs.update_log(pid_tgid, SyscallEvent::Exit(exit_info)); + let event_queue = logs.log.get(&pid_tgid).unwrap(); let len = event_queue.len(); if len >= 2 { let enter_event = &event_queue[len - 2]; match enter_event { SyscallEvent::Enter0(e) => { on_event_update_rw_sets(SyscallInfo::Event0 { - pid: e.pid as u64, + pid_tgid: e.pid_tgid as u64, ret: exit_info.ret, syscall_nr: e.syscall_nr, flags: e.flags as u32, @@ -756,7 +944,7 @@ pub fn event_stream_handler(rx: mpsc::Receiver>) -> Result< let path_cstr = unsafe { CStr::from_ptr(e.path.as_ptr()) }; on_event_update_rw_sets(SyscallInfo::Event1 { - pid: e.pid as u64, + pid_tgid: e.pid_tgid as u64, ret: exit_info.ret, syscall_nr: e.syscall_nr, flags: e.flags as u32, @@ -769,7 +957,7 @@ pub fn event_stream_handler(rx: mpsc::Receiver>) -> Result< let path2_cstr = unsafe { CStr::from_ptr(e.path2.as_ptr()) }; on_event_update_rw_sets(SyscallInfo::Event2 { - pid: e.pid as u64, + pid_tgid: e.pid_tgid as u64, ret: exit_info.ret, syscall_nr: e.syscall_nr, flags: e.flags as u32, diff --git a/src/main.rs b/src/main.rs index 4114a85..3e840ba 100644 --- a/src/main.rs +++ b/src/main.rs @@ -111,6 +111,12 @@ fn main() -> Result<()> { ctxt.init_pid(pid_tgid, cwd.clone()); // Also initialize with just the pid (lower 32 bits) since some events might use that ctxt.init_pid(target_pid as u64, cwd.clone()); + for entry in std::fs::read_dir(format!("/proc/{}/fd", target_pid))? { + let entry = entry?; + let fd: i32 = entry.file_name().to_string_lossy().parse().unwrap(); + let path = std::fs::read_link(entry.path())?; + ctxt.map_fds(target_pid, fd, path); + } } let skel_builder = HsTraceSkelBuilder::default(); @@ -205,7 +211,7 @@ fn main() -> Result<()> { Err(_) => {} } let _ = stream_handler.join(); - + let ctxt = CTXT.lock().unwrap(); let mut logs = LOGS.lock().unwrap(); logs.dump_log();