From b03011fcc39cb1fce1686f6c4ac180c218d611f3 Mon Sep 17 00:00:00 2001 From: Marcin Mielniczuk Date: Wed, 26 Jul 2017 09:53:11 +0200 Subject: Mark nix::sys::ptrace::ptrace as unsafe, add safe variants of source routines. These include: * PTRACE_TRACEME * PTRACE_CONT * PTRACE_ATTACH * PTRACE_SYSCALL --- src/sys/ptrace.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++++++- test/sys/test_ptrace.rs | 5 ++--- test/sys/test_wait.rs | 9 ++++----- 3 files changed, 55 insertions(+), 9 deletions(-) diff --git a/src/sys/ptrace.rs b/src/sys/ptrace.rs index 877bfcb0..d83c6e09 100644 --- a/src/sys/ptrace.rs +++ b/src/sys/ptrace.rs @@ -70,7 +70,7 @@ mod ffi { /// Performs a ptrace request. If the request in question is provided by a specialised function /// this function will return an unsupported operation error. -pub fn ptrace(request: ptrace::PtraceRequest, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result { +pub unsafe fn ptrace(request: ptrace::PtraceRequest, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result { use self::ptrace::*; match request { @@ -140,3 +140,51 @@ pub fn setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> { Err(e) => Err(e), } } + +/// Sets the process as traceable with `PTRACE_TRACEME` +pub fn traceme() -> Result<()> { + unsafe { + ptrace( + ptrace::PTRACE_TRACEME, + Pid::from_raw(0), + ptr::null_mut(), + ptr::null_mut(), + ).map(|_| ()) // ignore the useless return value + } +} + +/// Makes the `PTRACE_SYSCALL` request to ptrace +pub fn syscall(pid: Pid) -> Result<()> { + unsafe { + ptrace( + ptrace::PTRACE_SYSCALL, + pid, + ptr::null_mut(), + ptr::null_mut(), + ).map(|_| ()) // ignore the useless return value + } +} + +/// Makes the `PTRACE_ATTACH` request to ptrace +pub fn attach(pid: Pid) -> Result<()> { + unsafe { + ptrace( + ptrace::PTRACE_ATTACH, + pid, + ptr::null_mut(), + ptr::null_mut(), + ).map(|_| ()) // ignore the useless return value + } +} + +/// Makes the `PTRACE_CONT` request to ptrace +pub fn cont(pid: Pid) -> Result<()> { + unsafe { + ptrace( + ptrace::PTRACE_CONT, + pid, + ptr::null_mut(), + ptr::null_mut(), + ).map(|_| ()) // ignore the useless return value + } +} diff --git a/test/sys/test_ptrace.rs b/test/sys/test_ptrace.rs index 0614c13f..16a60ba7 100644 --- a/test/sys/test_ptrace.rs +++ b/test/sys/test_ptrace.rs @@ -3,14 +3,13 @@ use nix::errno::Errno; use nix::unistd::getpid; use nix::sys::ptrace; -use std::{mem, ptr}; +use std::mem; #[test] fn test_ptrace() { - use nix::sys::ptrace::ptrace::PTRACE_ATTACH; // Just make sure ptrace can be called at all, for now. // FIXME: qemu-user doesn't implement ptrace on all arches, so permit ENOSYS - let err = ptrace::ptrace(PTRACE_ATTACH, getpid(), ptr::null_mut(), ptr::null_mut()).unwrap_err(); + let err = ptrace::attach(getpid()).unwrap_err(); assert!(err == Error::Sys(Errno::EPERM) || err == Error::Sys(Errno::ENOSYS)); } diff --git a/test/sys/test_wait.rs b/test/sys/test_wait.rs index 8d2ca85f..4a7379c1 100644 --- a/test/sys/test_wait.rs +++ b/test/sys/test_wait.rs @@ -47,11 +47,10 @@ mod ptrace { use nix::sys::wait::*; use nix::unistd::*; use nix::unistd::ForkResult::*; - use std::{ptr, process}; use libc::_exit; fn ptrace_child() -> ! { - ptrace::ptrace(PTRACE_TRACEME, Pid::from_raw(0), ptr::null_mut(), ptr::null_mut()).unwrap(); + ptrace::traceme().unwrap(); // As recommended by ptrace(2), raise SIGTRAP to pause the child // until the parent is ready to continue let _ = raise(SIGTRAP); @@ -65,13 +64,13 @@ mod ptrace { assert!(ptrace::setoptions(child, PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXIT).is_ok()); // First, stop on the next system call, which will be exit() - assert!(ptrace::ptrace(PTRACE_SYSCALL, child, ptr::null_mut(), ptr::null_mut()).is_ok()); + assert!(ptrace::syscall(child).is_ok()); assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child))); // Then get the ptrace event for the process exiting - assert!(ptrace::ptrace(PTRACE_CONT, child, ptr::null_mut(), ptr::null_mut()).is_ok()); + assert!(ptrace::cont(child).is_ok()); assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceEvent(child, SIGTRAP, PTRACE_EVENT_EXIT))); // Finally get the normal wait() result, now that the process has exited - assert!(ptrace::ptrace(PTRACE_CONT, child, ptr::null_mut(), ptr::null_mut()).is_ok()); + assert!(ptrace::cont(child).is_ok()); assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 0))); } -- cgit v1.2.3