Skip to content

Commit

Permalink
Add ptrace::syscall test
Browse files Browse the repository at this point in the history
  • Loading branch information
frangio committed Jun 17, 2019
1 parent 26385ee commit c1a07b9
Showing 1 changed file with 73 additions and 0 deletions.
73 changes: 73 additions & 0 deletions test/sys/test_ptrace.rs
Expand Up @@ -105,3 +105,76 @@ fn test_ptrace_cont() {
},
}
}

// ptrace::setoptions needed to trace syscalls is only available in these platforms
#[cfg(any(target_os = "android", target_os = "linux"))]
#[test]
fn test_ptrace_syscall() {
use nix::sys::signal::kill;
use nix::sys::ptrace;
use nix::sys::signal::Signal;
use nix::sys::wait::{waitpid, WaitStatus};
use nix::unistd::fork;
use nix::unistd::getpid;
use nix::unistd::ForkResult::*;

let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");

// FIXME: qemu-user doesn't implement ptrace on all architectures
// and retunrs ENOSYS in this case.
// We (ab)use this behavior to detect the affected platforms
// and skip the test then.
// On valid platforms the ptrace call should return Errno::EPERM, this
// is already tested by `test_ptrace`.
let err = ptrace::attach(getpid()).unwrap_err();
if err == Error::Sys(Errno::ENOSYS) {
return;
}

match fork().expect("Error: Fork Failed") {
Child => {
ptrace::traceme().unwrap();
// first sigstop until parent is ready to continue
kill(getpid(), Signal::SIGSTOP).unwrap();
kill(getpid(), Signal::SIGTERM).unwrap();
},

Parent { child } => {
assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGSTOP)));

// set this option to recognize syscall-stops
ptrace::setoptions(child, ptrace::Options::PTRACE_O_TRACESYSGOOD).unwrap();

let get_syscall_id = || ptrace::getregs(child).unwrap().orig_rax as i64;


// getpid entry
ptrace::syscall(child, None).unwrap();
assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
assert_eq!(get_syscall_id(), libc::SYS_getpid);

// getpid exit
ptrace::syscall(child, None).unwrap();
assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
assert_eq!(get_syscall_id(), libc::SYS_getpid);

// kill entry
ptrace::syscall(child, None).unwrap();
assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
assert_eq!(get_syscall_id(), libc::SYS_kill);

// kill exit
ptrace::syscall(child, None).unwrap();
assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
assert_eq!(get_syscall_id(), libc::SYS_kill);

// receive signal
ptrace::syscall(child, None).unwrap();
assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTERM)));

// inject signal
ptrace::syscall(child, Signal::SIGTERM).unwrap();
assert_eq!(waitpid(child, None), Ok(WaitStatus::Signaled(child, Signal::SIGTERM, false)));
},
}
}

0 comments on commit c1a07b9

Please sign in to comment.