Add more syscalls
This commit is contained in:
parent
21c03b8d7b
commit
49615b5017
207
src/main.rs
207
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<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(())
|
||||
|
|
Loading…
Reference in New Issue