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 {
|
macro_rules! syscall_res_from_regs {
|
||||||
($regs:ident) => {
|
($regs:ident) => {
|
||||||
$regs.rax as i64
|
$regs.rax as i64
|
||||||
|
@ -267,7 +266,7 @@ pub struct ProcessState {
|
||||||
pub presyscall: bool,
|
pub presyscall: bool,
|
||||||
pub is_exec_successful: bool,
|
pub is_exec_successful: bool,
|
||||||
pub syscall: i64,
|
pub syscall: i64,
|
||||||
pub exec_data: Option<ExecData>,
|
pub pending_syscall_event: Vec<Event>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
@ -317,7 +316,7 @@ impl ProcessState {
|
||||||
presyscall: true,
|
presyscall: true,
|
||||||
is_exec_successful: false,
|
is_exec_successful: false,
|
||||||
syscall: -1,
|
syscall: -1,
|
||||||
exec_data: None,
|
pending_syscall_event: vec![],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -327,6 +326,16 @@ pub enum Event {
|
||||||
Fork { child: Pid },
|
Fork { child: Pid },
|
||||||
Exec { prog: PathBuf },
|
Exec { prog: PathBuf },
|
||||||
Exit { code: i32 },
|
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)]
|
#[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 {
|
impl Display for Event {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Event::Fork { child } => write!(f, "fork {child}"),
|
Event::Fork { child } => write!(f, "fork {child}"),
|
||||||
Event::Exec { prog } => write!(f, "exec {}", prog.to_string_lossy()),
|
Event::Exec { prog } => write!(f, "exec {}", prog.to_string_lossy()),
|
||||||
Event::Exit { code } => write!(f, "exit with {code}"),
|
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<()> {
|
pub fn start_root_process(&mut self, args: Vec<String>) -> anyhow::Result<()> {
|
||||||
log::trace!("start_root_process: {:?}", args);
|
log::trace!("start_root_process: {:?}", args);
|
||||||
|
|
||||||
|
@ -520,8 +554,7 @@ impl Tracer {
|
||||||
// So we need to determine whether exec is successful here.
|
// So we need to determine whether exec is successful here.
|
||||||
// PTRACE_EVENT_EXEC only happens for successful exec.
|
// PTRACE_EVENT_EXEC only happens for successful exec.
|
||||||
p.is_exec_successful = true;
|
p.is_exec_successful = true;
|
||||||
let prog = p.exec_data.as_ref().unwrap().filename.clone();
|
self.drain_syscall_events(pid, Box::new(|_| {}));
|
||||||
self.log_root(pid, Event::Exec { prog });
|
|
||||||
// Don't use seccomp_aware_cont here because that will skip the next syscall exit stop
|
// Don't use seccomp_aware_cont here because that will skip the next syscall exit stop
|
||||||
self.syscall_enter_cont(pid)?;
|
self.syscall_enter_cont(pid)?;
|
||||||
}
|
}
|
||||||
|
@ -560,12 +593,10 @@ impl Tracer {
|
||||||
let me = getpid();
|
let me = getpid();
|
||||||
setpgid(me, me)?;
|
setpgid(me, me)?;
|
||||||
traceme()?;
|
traceme()?;
|
||||||
log::trace!("traceme setup!");
|
|
||||||
if 0 != unsafe { raise(SIGSTOP) } {
|
if 0 != unsafe { raise(SIGSTOP) } {
|
||||||
log::error!("raise failed!");
|
log::error!("raise failed!");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
log::trace!("raise success!");
|
|
||||||
|
|
||||||
let args = args
|
let args = args
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -592,40 +623,76 @@ impl Tracer {
|
||||||
let syscallno = syscall_no_from_regs!(regs);
|
let syscallno = syscall_no_from_regs!(regs);
|
||||||
p.syscall = syscallno;
|
p.syscall = syscallno;
|
||||||
// log::trace!("pre syscall: {syscallno}");
|
// log::trace!("pre syscall: {syscallno}");
|
||||||
if syscallno == nix::libc::SYS_execveat {
|
match syscallno {
|
||||||
log::trace!("pre execveat");
|
nix::libc::SYS_execveat => {
|
||||||
// int execveat(int dirfd, const char *pathname,
|
log::trace!("pre execveat");
|
||||||
// char *const _Nullable argv[],
|
// int execveat(int dirfd, const char *pathname,
|
||||||
// char *const _Nullable envp[],
|
// char *const _Nullable argv[],
|
||||||
// int flags);
|
// char *const _Nullable envp[],
|
||||||
let dirfd = syscall_arg!(regs, 0) as i32;
|
// int flags);
|
||||||
let pathname = read_string(pid, syscall_arg!(regs, 1) as AddressType)?;
|
let dirfd = syscall_arg!(regs, 0) as i32;
|
||||||
let argv = read_string_array(pid, syscall_arg!(regs, 2) as AddressType)?;
|
let pathname = read_string(pid, syscall_arg!(regs, 1) as AddressType)?;
|
||||||
let envp = read_string_array(pid, syscall_arg!(regs, 3) as AddressType)?;
|
//let argv = read_string_array(pid, syscall_arg!(regs, 2) as AddressType)?;
|
||||||
let flags = syscall_arg!(regs, 4) as i32;
|
//let envp = read_string_array(pid, syscall_arg!(regs, 3) as AddressType)?;
|
||||||
let filename = resolve_filename_at_fd(pid, pathname, dirfd, flags)?;
|
let flags = syscall_arg!(regs, 4) as i32;
|
||||||
let interpreters = read_interpreter_recursive(&filename);
|
let filename = resolve_filename_at_fd(pid, pathname, dirfd, flags)?;
|
||||||
p.exec_data = Some(ExecData {
|
//let interpreters = read_interpreter_recursive(&filename);
|
||||||
filename,
|
p.pending_syscall_event.push(Event::Exec {
|
||||||
argv,
|
prog: filename,
|
||||||
envp,
|
});
|
||||||
cwd: read_cwd(pid)?,
|
}
|
||||||
interpreters,
|
nix::libc::SYS_execve => {
|
||||||
});
|
log::trace!("pre execve");
|
||||||
} else if syscallno == nix::libc::SYS_execve {
|
let filename = read_pathbuf(pid, syscall_arg!(regs, 0) as AddressType)?;
|
||||||
log::trace!("pre execve",);
|
//let argv = read_string_array(pid, syscall_arg!(regs, 1) as AddressType)?;
|
||||||
let filename = read_pathbuf(pid, syscall_arg!(regs, 0) as AddressType)?;
|
//let envp = read_string_array(pid, syscall_arg!(regs, 2) as AddressType)?;
|
||||||
let argv = read_string_array(pid, syscall_arg!(regs, 1) as AddressType)?;
|
//let interpreters = read_interpreter_recursive(&filename);
|
||||||
let envp = read_string_array(pid, syscall_arg!(regs, 2) as AddressType)?;
|
p.pending_syscall_event.push(Event::Exec {
|
||||||
let interpreters = read_interpreter_recursive(&filename);
|
prog: filename,
|
||||||
p.exec_data = Some(ExecData {
|
});
|
||||||
filename,
|
}
|
||||||
argv,
|
nix::libc::SYS_open => {
|
||||||
envp,
|
let path = read_pathbuf(pid, syscall_arg!(regs, 0) as AddressType)?;
|
||||||
cwd: read_cwd(pid)?,
|
p.pending_syscall_event.push(Event::FdOpen {
|
||||||
interpreters,
|
source: FdSource::File { path },
|
||||||
});
|
fd: -1,
|
||||||
} else if syscallno == SYS_clone || syscallno == SYS_clone3 {
|
});
|
||||||
|
}
|
||||||
|
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)?;
|
self.syscall_enter_cont(pid)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -636,24 +703,74 @@ impl Tracer {
|
||||||
// log::trace!("post syscall {}", p.syscall);
|
// log::trace!("post syscall {}", p.syscall);
|
||||||
let p = self.store.get_current_mut(pid).unwrap();
|
let p = self.store.get_current_mut(pid).unwrap();
|
||||||
p.presyscall = !p.presyscall;
|
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 => {
|
nix::libc::SYS_execve => {
|
||||||
log::trace!("post execve");
|
log::trace!("post execve");
|
||||||
// SAFETY: p.preexecve is false, so p.exec_data is Some
|
// SAFETY: p.preexecve is false, so p.exec_data is Some
|
||||||
p.exec_data = None;
|
|
||||||
p.is_exec_successful = false;
|
p.is_exec_successful = false;
|
||||||
// update comm
|
// update comm
|
||||||
p.comm = read_comm(pid)?;
|
p.comm = read_comm(pid)?;
|
||||||
|
None
|
||||||
}
|
}
|
||||||
nix::libc::SYS_execveat => {
|
nix::libc::SYS_execveat => {
|
||||||
log::trace!("post execveat");
|
log::trace!("post execveat");
|
||||||
p.exec_data = None;
|
|
||||||
p.is_exec_successful = false;
|
p.is_exec_successful = false;
|
||||||
// update comm
|
// update comm
|
||||||
p.comm = read_comm(pid)?;
|
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)?;
|
self.seccomp_aware_cont(pid)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
Loading…
Reference in New Issue