-
Notifications
You must be signed in to change notification settings - Fork 680
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
949: ptrace support for BSDs r=Susurrus a=xd009642 This PR adds support to the ptrace API for BSDs to close #947. It also adds a read and write method for reading and writing to a traced processes memory. The ptrace API created for linux offers this via a deprecated function so I added this so they can be feature equivalent without replicating a deprecated part of the API. Due to the differences in ptrace on BSD and linux I've made a ptrace module to keep things readable. Still to do - revert travis config to remove my feature branch and update the changelog. Co-authored-by: xd009642 <danielmckenna93@gmail.com>
- Loading branch information
Showing
7 changed files
with
257 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
use errno::Errno; | ||
use libc::{self, c_int}; | ||
use std::ptr; | ||
use sys::signal::Signal; | ||
use unistd::Pid; | ||
use Result; | ||
|
||
pub type RequestType = c_int; | ||
|
||
cfg_if! { | ||
if #[cfg(any(target_os = "dragonfly", | ||
target_os = "freebsd", | ||
target_os = "macos", | ||
target_os = "openbsd"))] { | ||
#[doc(hidden)] | ||
pub type AddressType = *mut ::libc::c_char; | ||
} else { | ||
#[doc(hidden)] | ||
pub type AddressType = *mut ::libc::c_void; | ||
} | ||
} | ||
|
||
libc_enum! { | ||
#[repr(i32)] | ||
/// Ptrace Request enum defining the action to be taken. | ||
pub enum Request { | ||
PT_TRACE_ME, | ||
PT_READ_I, | ||
PT_READ_D, | ||
#[cfg(target_os = "macos")] | ||
PT_READ_U, | ||
PT_WRITE_I, | ||
PT_WRITE_D, | ||
#[cfg(target_os = "macos")] | ||
PT_WRITE_U, | ||
PT_CONTINUE, | ||
PT_KILL, | ||
#[cfg(any(any(target_os = "dragonfly", | ||
target_os = "freebsd", | ||
target_os = "macos"), | ||
all(target_os = "openbsd", target_arch = "x86_64"), | ||
all(target_os = "netbsd", any(target_arch = "x86_64", | ||
target_arch = "powerpc"))))] | ||
PT_STEP, | ||
PT_ATTACH, | ||
PT_DETACH, | ||
#[cfg(target_os = "macos")] | ||
PT_SIGEXC, | ||
#[cfg(target_os = "macos")] | ||
PT_THUPDATE, | ||
#[cfg(target_os = "macos")] | ||
PT_ATTACHEXC | ||
} | ||
} | ||
|
||
unsafe fn ptrace_other( | ||
request: Request, | ||
pid: Pid, | ||
addr: AddressType, | ||
data: c_int, | ||
) -> Result<c_int> { | ||
Errno::result(libc::ptrace( | ||
request as RequestType, | ||
libc::pid_t::from(pid), | ||
addr, | ||
data, | ||
)).map(|_| 0) | ||
} | ||
|
||
/// Sets the process as traceable, as with `ptrace(PT_TRACEME, ...)` | ||
/// | ||
/// Indicates that this process is to be traced by its parent. | ||
/// This is the only ptrace request to be issued by the tracee. | ||
pub fn traceme() -> Result<()> { | ||
unsafe { ptrace_other(Request::PT_TRACE_ME, Pid::from_raw(0), ptr::null_mut(), 0).map(|_| ()) } | ||
} | ||
|
||
/// Attach to a running process, as with `ptrace(PT_ATTACH, ...)` | ||
/// | ||
/// Attaches to the process specified in pid, making it a tracee of the calling process. | ||
pub fn attach(pid: Pid) -> Result<()> { | ||
unsafe { ptrace_other(Request::PT_ATTACH, pid, ptr::null_mut(), 0).map(|_| ()) } | ||
} | ||
|
||
/// Detaches the current running process, as with `ptrace(PT_DETACH, ...)` | ||
/// | ||
/// Detaches from the process specified in pid allowing it to run freely | ||
pub fn detach(pid: Pid) -> Result<()> { | ||
unsafe { ptrace_other(Request::PT_DETACH, pid, ptr::null_mut(), 0).map(|_| ()) } | ||
} | ||
|
||
/// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)` | ||
/// | ||
/// Continues the execution of the process with PID `pid`, optionally | ||
/// delivering a signal specified by `sig`. | ||
pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { | ||
let data = match sig.into() { | ||
Some(s) => s as c_int, | ||
None => 0, | ||
}; | ||
unsafe { | ||
// Ignore the useless return value | ||
ptrace_other(Request::PT_CONTINUE, pid, 1 as AddressType, data).map(|_| ()) | ||
} | ||
} | ||
|
||
/// Issues a kill request as with `ptrace(PT_KILL, ...)` | ||
/// | ||
/// This request is equivalent to `ptrace(PT_CONTINUE, ..., SIGKILL);` | ||
pub fn kill(pid: Pid) -> Result<()> { | ||
unsafe { | ||
ptrace_other(Request::PT_KILL, pid, 0 as AddressType, 0).map(|_| ()) | ||
} | ||
} | ||
|
||
/// Move the stopped tracee process forward by a single step as with | ||
/// `ptrace(PT_STEP, ...)` | ||
/// | ||
/// Advances the execution of the process with PID `pid` by a single step optionally delivering a | ||
/// signal specified by `sig`. | ||
/// | ||
/// # Example | ||
/// ```rust | ||
/// extern crate nix; | ||
/// use nix::sys::ptrace::step; | ||
/// use nix::unistd::Pid; | ||
/// use nix::sys::signal::Signal; | ||
/// use nix::sys::wait::*; | ||
/// fn main() { | ||
/// // If a process changes state to the stopped state because of a SIGUSR1 | ||
/// // signal, this will step the process forward and forward the user | ||
/// // signal to the stopped process | ||
/// match waitpid(Pid::from_raw(-1), None) { | ||
/// Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => { | ||
/// let _ = step(pid, Signal::SIGUSR1); | ||
/// } | ||
/// _ => {}, | ||
/// } | ||
/// } | ||
/// ``` | ||
#[cfg( | ||
any( | ||
any(target_os = "dragonfly", target_os = "freebsd", target_os = "macos"), | ||
all(target_os = "openbsd", target_arch = "x86_64"), | ||
all(target_os = "netbsd", | ||
any(target_arch = "x86_64", target_arch = "powerpc") | ||
) | ||
) | ||
)] | ||
pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { | ||
let data = match sig.into() { | ||
Some(s) => s as c_int, | ||
None => 0, | ||
}; | ||
unsafe { ptrace_other(Request::PT_STEP, pid, ptr::null_mut(), data).map(|_| ()) } | ||
} | ||
|
||
/// Reads a word from a processes memory at the given address | ||
pub fn read(pid: Pid, addr: AddressType) -> Result<c_int> { | ||
unsafe { | ||
// Traditionally there was a difference between reading data or | ||
// instruction memory but not in modern systems. | ||
ptrace_other(Request::PT_READ_D, pid, addr, 0) | ||
} | ||
} | ||
|
||
/// Writes a word into the processes memory at the given address | ||
pub fn write(pid: Pid, addr: AddressType, data: c_int) -> Result<()> { | ||
unsafe { ptrace_other(Request::PT_WRITE_D, pid, addr, data).map(|_| ()) } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
///! Provides helpers for making ptrace system calls | ||
#[cfg(any(target_os = "android", target_os = "linux"))] | ||
mod linux; | ||
|
||
#[cfg(any(target_os = "android", target_os = "linux"))] | ||
pub use self::linux::*; | ||
|
||
#[cfg(any(target_os = "dragonfly", | ||
target_os = "freebsd", | ||
target_os = "macos", | ||
target_os = "netbsd", | ||
target_os = "openbsd"))] | ||
mod bsd; | ||
|
||
#[cfg(any(target_os = "dragonfly", | ||
target_os = "freebsd", | ||
target_os = "macos", | ||
target_os = "netbsd", | ||
target_os = "openbsd" | ||
))] | ||
pub use self::bsd::*; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters