Skip to content

Commit

Permalink
Added ptrace utilities.
Browse files Browse the repository at this point in the history
Some ptrace functions return structures through the data argument. This commit adds utilities to return data through this mechanism and function specialisations for a few of these functions (getting event messages or the siginfo_t struct). Once the next version of libc is released these utilities will be expanded to include the fpregs and user_regs structs.

Ptrace requests that are now satisfied by a more specific public function will return an unsupported operation error. This has involved adding an UnsupportedOperation to the nix::Error enum and removed the mapping from Error to Errno and from Error to std::io::Error.
  • Loading branch information
xd009642 committed Jun 13, 2017
1 parent 6783ffc commit 43a2943
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 20 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
([#556](https://github.com/nix-rust/nix/pull/556)
- Added `nix::ptr::openpty`
([#456](https://github.com/nix-rust/nix/pull/456))
- Added `nix::ptrace::{ptrace_get_data, ptrace_getsiginfo, ptrace_setsiginfo
and nix::Error::UnsupportedOperation}`
([#614](https://github.com/nix-rust/nix/pull/614))

### Changed
- Marked `sys::mman::{ mmap, munmap, madvise, munlock, msync }` as unsafe.
Expand All @@ -29,6 +32,10 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Changed type signature of `sys::select::FdSet::contains` to make `self`
immutable ([#564](https://github.com/nix-rust/nix/pull/564))

### Removed
- Removed io::Error from nix::Error and conversion from nix::Error to Errno
([#614](https://github.com/nix-rust/nix/pull/614))

### Fixed
- Fixed multiple issues compiling under different archetectures and OSes.
Now compiles on Linux/MIPS ([#538](https://github.com/nix-rust/nix/pull/538)),
Expand Down
24 changes: 5 additions & 19 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ use std::{ptr, result};
use std::ffi::{CStr, OsStr};
use std::path::{Path, PathBuf};
use std::os::unix::ffi::OsStrExt;
use std::io;
use std::fmt;
use std::error;
use libc::PATH_MAX;
Expand All @@ -97,6 +96,9 @@ pub enum Error {
/// The operation involved a conversion to Rust's native String type, which failed because the
/// string did not contain all valid UTF-8.
InvalidUtf8,
/// The operation is not supported by Nix, in this instance either use the libc bindings or
/// consult the module documentation to see if there is a more appropriate interface available.
UnsupportedOperation,
}

impl Error {
Expand All @@ -116,14 +118,6 @@ impl Error {
Error::Sys(errno::EINVAL)
}

/// Get the errno associated with this error
pub fn errno(&self) -> errno::Errno {
match *self {
Error::InvalidPath => errno::Errno::EINVAL,
Error::InvalidUtf8 => errno::Errno::UnknownErrno,
Error::Sys(errno) => errno,
}
}
}

impl From<errno::Errno> for Error {
Expand All @@ -139,6 +133,7 @@ impl error::Error for Error {
match self {
&Error::InvalidPath => "Invalid path",
&Error::InvalidUtf8 => "Invalid UTF-8 string",
&Error::UnsupportedOperation => "Unsupported Operation",
&Error::Sys(ref errno) => errno.desc(),
}
}
Expand All @@ -149,21 +144,12 @@ impl fmt::Display for Error {
match self {
&Error::InvalidPath => write!(f, "Invalid path"),
&Error::InvalidUtf8 => write!(f, "Invalid UTF-8 string"),
&Error::UnsupportedOperation => write!(f, "Unsupported Operation"),
&Error::Sys(errno) => write!(f, "{:?}: {}", errno, errno.desc()),
}
}
}

impl From<Error> for io::Error {
fn from(err: Error) -> Self {
match err {
Error::InvalidPath => io::Error::new(io::ErrorKind::InvalidInput, err),
Error::InvalidUtf8 => io::Error::new(io::ErrorKind::Other, err),
Error::Sys(errno) => io::Error::from_raw_os_error(errno as i32),
}
}
}

pub trait NixPath {
fn len(&self) -> usize;

Expand Down
45 changes: 44 additions & 1 deletion src/sys/ptrace.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::{mem, ptr};
use {Errno, Error, Result};
use libc::{pid_t, c_void, c_long};
use libc::{pid_t, c_void, c_long, siginfo_t};

#[cfg(all(target_os = "linux",
any(target_arch = "x86",
Expand Down Expand Up @@ -71,11 +72,14 @@ 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_t, addr: *mut c_void, data: *mut c_void) -> Result<c_long> {
use self::ptrace::*;

match request {
PTRACE_PEEKTEXT | PTRACE_PEEKDATA | PTRACE_PEEKUSER => ptrace_peek(request, pid, addr, data),
PTRACE_GETSIGINFO | PTRACE_GETEVENTMSG | PTRACE_SETSIGINFO | PTRACE_SETOPTIONS => Err(Error::UnsupportedOperation),
_ => ptrace_other(request, pid, addr, data)
}
}
Expand All @@ -91,6 +95,20 @@ fn ptrace_peek(request: ptrace::PtraceRequest, pid: pid_t, addr: *mut c_void, da
}
}

/// Function for ptrace requests that return values from the data field.
/// Some ptrace get requests populate structs or larger elements than c_long
/// and therefore use the data field to return values. This function handles these
/// requests.
fn ptrace_get_data<T>(request: ptrace::PtraceRequest, pid: pid_t) -> Result<T> {
// Creates an uninitialized pointer to store result in
let data: Box<T> = Box::new(unsafe { mem::uninitialized() });
let data: *mut c_void = unsafe { mem::transmute(data) };
ptrace(request, pid, ptr::null_mut(), data)?;
// Convert back into the original data format and return unboxed value
let data: Box<T> = unsafe { mem::transmute(data) };
Ok(*data)
}

fn ptrace_other(request: ptrace::PtraceRequest, pid: pid_t, addr: *mut c_void, data: *mut c_void) -> Result<c_long> {
Errno::result(unsafe { ffi::ptrace(request, pid, addr, data) }).map(|_| 0)
}
Expand All @@ -102,3 +120,28 @@ pub fn ptrace_setoptions(pid: pid_t, options: ptrace::PtraceOptions) -> Result<(

ptrace(PTRACE_SETOPTIONS, pid, ptr::null_mut(), options as *mut c_void).map(drop)
}

/// Gets a ptrace event as described by `ptrace(PTRACE_GETEVENTMSG,...)`
pub fn ptrace_getevent(pid: pid_t) -> Result<c_long> {
use self::ptrace::*;
ptrace_get_data::<c_long>(PTRACE_GETEVENTMSG, pid)
}

/// Get siginfo as with `ptrace(PTRACE_GETSIGINFO,...)`
pub fn ptrace_getsiginfo(pid: pid_t) -> Result<siginfo_t> {
use self::ptrace::*;
ptrace_get_data::<siginfo_t>(PTRACE_GETSIGINFO, pid)
}

/// Set siginfo as with `ptrace(PTRACE_SETSIGINFO,...)`
pub fn ptrace_setsiginfo(pid: pid_t, sig: &siginfo_t) -> Result<()> {
use self::ptrace::*;
let ret = unsafe{
Errno::clear();
ffi::ptrace(PTRACE_SETSIGINFO, pid, ptr::null_mut(), sig as *const _ as *const c_void)
};
match Errno::result(ret) {
Ok(_) => Ok(()),
Err(e) => Err(e),
}
}

0 comments on commit 43a2943

Please sign in to comment.