diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-12-01 04:45:41 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-12-01 04:45:41 +0000 |
commit | 0ce45876eced99438f89631f63831e75012539c5 (patch) | |
tree | dc604391947282743dbac3d06679c965a0c3c73e /test/sys/test_ptrace.rs | |
parent | f3bf1df774a6cb89cf04dced385ec073908508b0 (diff) | |
parent | 7f3ee09eec10ef5319a7b1d9c358f50638eb1471 (diff) | |
download | nix-0ce45876eced99438f89631f63831e75012539c5.zip |
Merge #1083
1083: Allow signal injection in ptrace::syscall and ptrace::detach r=asomers a=frangio
Fixes #1049
Should I add tests for this functionality?
By the way, I noticed that the BSD module doesn't have `ptrace::syscall`. I couldn't find a reason behind this in #949. Should we add it?
Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
Diffstat (limited to 'test/sys/test_ptrace.rs')
-rw-r--r-- | test/sys/test_ptrace.rs | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/test/sys/test_ptrace.rs b/test/sys/test_ptrace.rs index b875e323..cb2f04e9 100644 --- a/test/sys/test_ptrace.rs +++ b/test/sys/test_ptrace.rs @@ -112,3 +112,63 @@ fn test_ptrace_cont() { }, } } + +// ptrace::{setoptions, getregs} are only available in these platforms +#[cfg(all(target_os = "linux", + any(target_arch = "x86_64", + target_arch = "x86"), + target_env = "gnu"))] +#[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"); + + match fork().expect("Error: Fork Failed") { + Child => { + ptrace::traceme().unwrap(); + // first sigstop until parent is ready to continue + let pid = getpid(); + kill(pid, Signal::SIGSTOP).unwrap(); + kill(pid, Signal::SIGTERM).unwrap(); + unsafe { ::libc::_exit(0); } + }, + + 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(); + + #[cfg(target_pointer_width = "64")] + let get_syscall_id = || ptrace::getregs(child).unwrap().orig_rax as i64; + + #[cfg(target_pointer_width = "32")] + let get_syscall_id = || ptrace::getregs(child).unwrap().orig_eax as i32; + + // 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))); + }, + } +} |