From 49615b5017aacc81175ab861c542cc4d8da03011 Mon Sep 17 00:00:00 2001 From: Audrey Dutcher Date: Thu, 11 Apr 2024 21:25:44 -0700 Subject: [PATCH] Add more syscalls --- src/main.rs | 207 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 162 insertions(+), 45 deletions(-) diff --git a/src/main.rs b/src/main.rs index 2159dfc..d19c3c7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -109,7 +109,6 @@ macro_rules! syscall_no_from_regs { }; } -#[allow(unused)] macro_rules! syscall_res_from_regs { ($regs:ident) => { $regs.rax as i64 @@ -267,7 +266,7 @@ pub struct ProcessState { pub presyscall: bool, pub is_exec_successful: bool, pub syscall: i64, - pub exec_data: Option, + pub pending_syscall_event: Vec, } #[derive(Debug, Clone, PartialEq)] @@ -317,7 +316,7 @@ impl ProcessState { presyscall: true, is_exec_successful: false, syscall: -1, - exec_data: None, + pending_syscall_event: vec![], }) } } @@ -327,6 +326,16 @@ pub enum Event { Fork { child: Pid }, Exec { prog: PathBuf }, Exit { code: i32 }, + FdOpen { fd: i32, source: FdSource }, + FdDup { oldfd: i32, newfd: i32 }, + FdClose { fd: i32 }, + FdRead { fd: i32 }, + FdWrite { fd: i32 }, +} + +#[derive(Debug)] +pub enum FdSource { + File { path: PathBuf }, } #[derive(Clone, Debug)] @@ -356,12 +365,25 @@ impl Display for LogEntry { } } +impl Display for FdSource { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + FdSource::File { path } => write!(f, "File {}", path.to_string_lossy()), + } + } +} + impl Display for Event { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { Event::Fork { child } => write!(f, "fork {child}"), Event::Exec { prog } => write!(f, "exec {}", prog.to_string_lossy()), Event::Exit { code } => write!(f, "exit with {code}"), + Event::FdOpen { fd, source } => write!(f, "open fd {fd} from {source}"), + Event::FdDup { oldfd, newfd } => write!(f, "dup fd {oldfd} to {newfd}"), + Event::FdClose { fd } => write!(f, "close fd {fd}"), + Event::FdRead { fd } => write!(f, "read from fd {fd}"), + Event::FdWrite { fd } => write!(f, "write to fd {fd}"), } } } @@ -403,6 +425,18 @@ impl Tracer { }) } + fn drain_syscall_events(&mut self, pid: Pid, mut filter: Box) { + let p = self.store.get_current_mut(pid).unwrap(); + for mut event in p.pending_syscall_event.drain(..) { + (filter)(&mut event); + self.log.push(LogEntry { + ident: Identifier { pid, machine: 0 }, + event, + timestamp: Instant::now().duration_since(self.start_time), + }); + } + } + pub fn start_root_process(&mut self, args: Vec) -> anyhow::Result<()> { log::trace!("start_root_process: {:?}", args); @@ -520,8 +554,7 @@ impl Tracer { // So we need to determine whether exec is successful here. // PTRACE_EVENT_EXEC only happens for successful exec. p.is_exec_successful = true; - let prog = p.exec_data.as_ref().unwrap().filename.clone(); - self.log_root(pid, Event::Exec { prog }); + self.drain_syscall_events(pid, Box::new(|_| {})); // Don't use seccomp_aware_cont here because that will skip the next syscall exit stop self.syscall_enter_cont(pid)?; } @@ -560,12 +593,10 @@ impl Tracer { let me = getpid(); setpgid(me, me)?; traceme()?; - log::trace!("traceme setup!"); if 0 != unsafe { raise(SIGSTOP) } { log::error!("raise failed!"); exit(-1); } - log::trace!("raise success!"); let args = args .into_iter() @@ -592,40 +623,76 @@ impl Tracer { let syscallno = syscall_no_from_regs!(regs); p.syscall = syscallno; // log::trace!("pre syscall: {syscallno}"); - if syscallno == nix::libc::SYS_execveat { - log::trace!("pre execveat"); - // int execveat(int dirfd, const char *pathname, - // char *const _Nullable argv[], - // char *const _Nullable envp[], - // int flags); - let dirfd = syscall_arg!(regs, 0) as i32; - let pathname = read_string(pid, syscall_arg!(regs, 1) as AddressType)?; - let argv = read_string_array(pid, syscall_arg!(regs, 2) as AddressType)?; - let envp = read_string_array(pid, syscall_arg!(regs, 3) as AddressType)?; - let flags = syscall_arg!(regs, 4) as i32; - let filename = resolve_filename_at_fd(pid, pathname, dirfd, flags)?; - let interpreters = read_interpreter_recursive(&filename); - p.exec_data = Some(ExecData { - filename, - argv, - envp, - cwd: read_cwd(pid)?, - interpreters, - }); - } else if syscallno == nix::libc::SYS_execve { - log::trace!("pre execve",); - let filename = read_pathbuf(pid, syscall_arg!(regs, 0) as AddressType)?; - let argv = read_string_array(pid, syscall_arg!(regs, 1) as AddressType)?; - let envp = read_string_array(pid, syscall_arg!(regs, 2) as AddressType)?; - let interpreters = read_interpreter_recursive(&filename); - p.exec_data = Some(ExecData { - filename, - argv, - envp, - cwd: read_cwd(pid)?, - interpreters, - }); - } else if syscallno == SYS_clone || syscallno == SYS_clone3 { + match syscallno { + nix::libc::SYS_execveat => { + log::trace!("pre execveat"); + // int execveat(int dirfd, const char *pathname, + // char *const _Nullable argv[], + // char *const _Nullable envp[], + // int flags); + let dirfd = syscall_arg!(regs, 0) as i32; + let pathname = read_string(pid, syscall_arg!(regs, 1) as AddressType)?; + //let argv = read_string_array(pid, syscall_arg!(regs, 2) as AddressType)?; + //let envp = read_string_array(pid, syscall_arg!(regs, 3) as AddressType)?; + let flags = syscall_arg!(regs, 4) as i32; + let filename = resolve_filename_at_fd(pid, pathname, dirfd, flags)?; + //let interpreters = read_interpreter_recursive(&filename); + p.pending_syscall_event.push(Event::Exec { + prog: filename, + }); + } + nix::libc::SYS_execve => { + log::trace!("pre execve"); + let filename = read_pathbuf(pid, syscall_arg!(regs, 0) as AddressType)?; + //let argv = read_string_array(pid, syscall_arg!(regs, 1) as AddressType)?; + //let envp = read_string_array(pid, syscall_arg!(regs, 2) as AddressType)?; + //let interpreters = read_interpreter_recursive(&filename); + p.pending_syscall_event.push(Event::Exec { + prog: filename, + }); + } + nix::libc::SYS_open => { + let path = read_pathbuf(pid, syscall_arg!(regs, 0) as AddressType)?; + p.pending_syscall_event.push(Event::FdOpen { + source: FdSource::File { path }, + fd: -1, + }); + } + nix::libc::SYS_openat => { + let dirfd = syscall_arg!(regs, 0) as i32; + let pathname = read_string(pid, syscall_arg!(regs, 1) as AddressType)?; + let flags = syscall_arg!(regs, 2) as i32; + let path = resolve_filename_at_fd(pid, pathname, dirfd, flags)?; + p.pending_syscall_event.push(Event::FdOpen { + source: FdSource::File { path }, + fd: 0, + }); + } + nix::libc::SYS_read | nix::libc::SYS_readv | nix::libc::SYS_preadv | nix::libc::SYS_preadv2 => { + let fd = syscall_arg!(regs, 0) as i32; + p.pending_syscall_event.push(Event::FdRead { fd }); + } + nix::libc::SYS_write | nix::libc::SYS_writev | nix::libc::SYS_pwritev | nix::libc::SYS_pwritev2 => { + let fd = syscall_arg!(regs, 0) as i32; + p.pending_syscall_event.push(Event::FdWrite { fd }); + } + nix::libc::SYS_dup | nix::libc::SYS_dup2 | nix::libc::SYS_dup3 => { + let oldfd = syscall_arg!(regs, 0) as i32; + p.pending_syscall_event.push(Event::FdDup { oldfd, newfd: -1 }); + } + nix::libc::SYS_fcntl => { + let fd = syscall_arg!(regs, 0) as i32; + let cmd = syscall_arg!(regs, 1) as i32; + match cmd { + nix::libc::F_DUPFD => p.pending_syscall_event.push(Event::FdDup { oldfd: fd, newfd: -1 }), + _ => {} + } + } + nix::libc::SYS_close => { + let fd = syscall_arg!(regs, 0) as i32; + p.pending_syscall_event.push(Event::FdClose { fd }); + } + _ => {} } self.syscall_enter_cont(pid)?; Ok(()) @@ -636,24 +703,74 @@ impl Tracer { // log::trace!("post syscall {}", p.syscall); let p = self.store.get_current_mut(pid).unwrap(); p.presyscall = !p.presyscall; + let regs = match ptrace::getregs(pid) { + Ok(regs) => regs, + Err(Errno::ESRCH) => { + log::info!("ptrace getregs failed: {pid}, ESRCH, child probably gone!"); + return Ok(()); + } + e => e?, + }; + let result = syscall_res_from_regs!(regs); - match p.syscall { + let filter: Option> = match p.syscall { nix::libc::SYS_execve => { log::trace!("post execve"); // SAFETY: p.preexecve is false, so p.exec_data is Some - p.exec_data = None; p.is_exec_successful = false; // update comm p.comm = read_comm(pid)?; + None } nix::libc::SYS_execveat => { log::trace!("post execveat"); - p.exec_data = None; p.is_exec_successful = false; // update comm p.comm = read_comm(pid)?; + None } - _ => (), + nix::libc::SYS_open | nix::libc::SYS_openat => { + if result >= 0 { + Some(Box::new(move |event| match event { + Event::FdOpen { fd: ref mut dest, ..} => { *dest = result as i32; } + _ => {} + })) + } else { + None + } + } + nix::libc::SYS_dup | nix::libc::SYS_dup2 | nix::libc::SYS_dup3 => { + if result >= 0 { + Some(Box::new(move |event| match event { + Event::FdDup { newfd: ref mut dest, ..} => { *dest = result as i32; } + _ => {} + })) + } else { + None + } + } + nix::libc::SYS_fcntl => { + if result >= 0 { + Some(Box::new(move |event| match event { + Event::FdDup { newfd: ref mut dest, ..} => { *dest = result as i32; } + _ => {} + })) + } else { + None + } + } + _ => { + if result >= 0 { + Some(Box::new(|_| {})) + } else { + None + } + } + }; + if let Some(filter) = filter { + self.drain_syscall_events(pid, filter); + } else { + p.pending_syscall_event.clear(); } self.seccomp_aware_cont(pid)?; Ok(())