Add more syscalls

This commit is contained in:
Audrey 2024-04-11 21:25:44 -07:00
parent 21c03b8d7b
commit 49615b5017
1 changed files with 162 additions and 45 deletions

View File

@ -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<ExecData>,
pub pending_syscall_event: Vec<Event>,
}
#[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<dyn FnMut(&mut Event)>) {
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<String>) -> 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<Box<dyn FnMut(&mut Event)>> = 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(())