Skip to content

Commit

Permalink
Merge #614
Browse files Browse the repository at this point in the history
614: Added ptrace utilities. r=Susurrus

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.

Due to the need to use unsafe blocks to utilise these ptrace features I feel these are good candidates for inclusion into rust-nix
  • Loading branch information
bors[bot] committed Jun 13, 2017
2 parents 6783ffc + 43a2943 commit 06850b2
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 06850b2

Please sign in to comment.