Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Move Ptrace{Request, Event, Options} into enums and bitflags. #461

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 80 additions & 59 deletions src/sys/ptrace.rs
Original file line number Diff line number Diff line change
@@ -1,66 +1,87 @@
use {Errno, Error, Result};
use libc::{pid_t, c_void, c_long};
use libc::{pid_t, c_int, c_void, c_long};

#[cfg(all(target_os = "linux",
any(target_arch = "x86",
target_arch = "x86_64",
target_arch = "arm")),
)]
#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod ptrace {
use libc::c_int;
use libc;

pub type PtraceRequest = c_int;
#[repr(u32)]
pub enum PtraceRequest {
PTRACE_TRACEME = libc::PTRACE_TRACEME,
PTRACE_PEEKTEXT = libc::PTRACE_PEEKTEXT,
PTRACE_PEEKDATA = libc::PTRACE_PEEKDATA,
PTRACE_PEEKUSER = libc::PTRACE_PEEKUSER,
PTRACE_POKETEXT = libc::PTRACE_POKETEXT,
PTRACE_POKEDATA = libc::PTRACE_POKEDATA,
PTRACE_POKEUSER = libc::PTRACE_POKEUSER,
PTRACE_CONT = libc::PTRACE_CONT,
PTRACE_KILL = libc::PTRACE_KILL,
PTRACE_SINGLESTEP = libc::PTRACE_SINGLESTEP,
PTRACE_GETREGS = libc::PTRACE_GETREGS,
PTRACE_SETREGS = libc::PTRACE_SETREGS,
PTRACE_GETFPREGS = libc::PTRACE_GETFPREGS,
PTRACE_SETFPREGS = libc::PTRACE_SETFPREGS,
PTRACE_ATTACH = libc::PTRACE_ATTACH,
PTRACE_DETACH = libc::PTRACE_DETACH,
PTRACE_GETFPXREGS = libc::PTRACE_GETFPXREGS,
PTRACE_SETFPXREGS = libc::PTRACE_SETFPXREGS,
PTRACE_SYSCALL = libc::PTRACE_SYSCALL,
PTRACE_SETOPTIONS = libc::PTRACE_SETOPTIONS,
PTRACE_GETEVENTMSG = libc::PTRACE_GETEVENTMSG,
PTRACE_GETSIGINFO = libc::PTRACE_GETSIGINFO,
PTRACE_SETSIGINFO = libc::PTRACE_SETSIGINFO,
PTRACE_GETREGSET = libc::PTRACE_GETREGSET,
PTRACE_SETREGSET = libc::PTRACE_SETREGSET,
PTRACE_SEIZE = libc::PTRACE_SEIZE,
PTRACE_INTERRUPT = libc::PTRACE_INTERRUPT,
PTRACE_LISTEN = libc::PTRACE_LISTEN,
PTRACE_PEEKSIGINFO = libc::PTRACE_PEEKSIGINFO,
}

pub const PTRACE_TRACEME: PtraceRequest = 0;
pub const PTRACE_PEEKTEXT: PtraceRequest = 1;
pub const PTRACE_PEEKDATA: PtraceRequest = 2;
pub const PTRACE_PEEKUSER: PtraceRequest = 3;
pub const PTRACE_POKETEXT: PtraceRequest = 4;
pub const PTRACE_POKEDATA: PtraceRequest = 5;
pub const PTRACE_POKEUSER: PtraceRequest = 6;
pub const PTRACE_CONT: PtraceRequest = 7;
pub const PTRACE_KILL: PtraceRequest = 8;
pub const PTRACE_SINGLESTEP: PtraceRequest = 9;
pub const PTRACE_GETREGS: PtraceRequest = 12;
pub const PTRACE_SETREGS: PtraceRequest = 13;
pub const PTRACE_GETFPREGS: PtraceRequest = 14;
pub const PTRACE_SETFPREGS: PtraceRequest = 15;
pub const PTRACE_ATTACH: PtraceRequest = 16;
pub const PTRACE_DETACH: PtraceRequest = 17;
pub const PTRACE_GETFPXREGS: PtraceRequest = 18;
pub const PTRACE_SETFPXREGS: PtraceRequest = 19;
pub const PTRACE_SYSCALL: PtraceRequest = 24;
pub const PTRACE_SETOPTIONS: PtraceRequest = 0x4200;
pub const PTRACE_GETEVENTMSG: PtraceRequest = 0x4201;
pub const PTRACE_GETSIGINFO: PtraceRequest = 0x4202;
pub const PTRACE_SETSIGINFO: PtraceRequest = 0x4203;
pub const PTRACE_GETREGSET: PtraceRequest = 0x4204;
pub const PTRACE_SETREGSET: PtraceRequest = 0x4205;
pub const PTRACE_SEIZE: PtraceRequest = 0x4206;
pub const PTRACE_INTERRUPT: PtraceRequest = 0x4207;
pub const PTRACE_LISTEN: PtraceRequest = 0x4208;
pub const PTRACE_PEEKSIGINFO: PtraceRequest = 0x4209;
// These aren't currently in libc.
#[cfg(any(target_os = "linux", target_os = "android"))]
#[derive(Eq, PartialEq, Clone, Copy, Debug)]
#[repr(u32)]
pub enum PtraceEvent {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should use #[repr(i32)] and thus consistently the type, which is used by the ffi function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't actually need the ffi function anymore, as ptrace has been added to the libc crate (https://doc.rust-lang.org/time/libc/fn.ptrace.html). u32 is consistent with libc's use of c_uint, but not with most C compilers' usage of int for enums (its not defined in the C spec afaik).

I feel like the cleanest way to do this is to remove nix's ffi and just wrap libc as it is and leave the rest up to libc upstream. Thoughts?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, we do defer to libc. I just think that the signatures of libc::ptrace und from_c_[u]int should use the same type (either c_int or c_uint), depending on libc::ptrace, because we have no influence on it.

PTRACE_EVENT_FORK = 1,
PTRACE_EVENT_VFORK = 2,
PTRACE_EVENT_CLONE = 3,
PTRACE_EVENT_EXEC = 4,
PTRACE_EVENT_VFORK_DONE = 5,
PTRACE_EVENT_EXIT = 6,
PTRACE_EVENT_SECCOMP = 7,
PTRACE_EVENT_STOP = 128,
}

pub type PtraceEvent = c_int;
#[cfg(any(target_os = "linux", target_os = "android"))]
impl PtraceEvent {
/// Creates a PtraceEvent from the extra bits of a wait status (status >> 16)
#[inline]
pub fn from_c_int(event: libc::c_uint) -> Option<PtraceEvent> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for ::nix::sys::signal::Signal we used Result<Signal> as a return type for the corresponding function. I think this is better, because I don't think anyone would intentionally put a wrong c_uint into from_c_int, so the None return type is never expected, thus should probably be an error type.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah sounds good I'll change that soon

use std::mem;

pub const PTRACE_EVENT_FORK: PtraceEvent = 1;
pub const PTRACE_EVENT_VFORK: PtraceEvent = 2;
pub const PTRACE_EVENT_CLONE: PtraceEvent = 3;
pub const PTRACE_EVENT_EXEC: PtraceEvent = 4;
pub const PTRACE_EVENT_VFORK_DONE: PtraceEvent = 5;
pub const PTRACE_EVENT_EXIT: PtraceEvent = 6;
pub const PTRACE_EVENT_SECCOMP: PtraceEvent = 6;
pub const PTRACE_EVENT_STOP: PtraceEvent = 128;
if (event >= PtraceEvent::PTRACE_EVENT_FORK as u32 &&
event <= PtraceEvent::PTRACE_EVENT_SECCOMP as u32)
|| event == PtraceEvent::PTRACE_EVENT_STOP as u32 {
Some(unsafe { mem::transmute(event) })
} else {
None
}
}
}

pub type PtraceOptions = c_int;
pub const PTRACE_O_TRACESYSGOOD: PtraceOptions = 1;
pub const PTRACE_O_TRACEFORK: PtraceOptions = (1 << PTRACE_EVENT_FORK);
pub const PTRACE_O_TRACEVFORK: PtraceOptions = (1 << PTRACE_EVENT_VFORK);
pub const PTRACE_O_TRACECLONE: PtraceOptions = (1 << PTRACE_EVENT_CLONE);
pub const PTRACE_O_TRACEEXEC: PtraceOptions = (1 << PTRACE_EVENT_EXEC);
pub const PTRACE_O_TRACEVFORKDONE: PtraceOptions = (1 << PTRACE_EVENT_VFORK_DONE);
pub const PTRACE_O_TRACEEXIT: PtraceOptions = (1 << PTRACE_EVENT_EXIT);
pub const PTRACE_O_TRACESECCOMP: PtraceOptions = (1 << PTRACE_EVENT_SECCOMP);
bitflags! {
flags PtraceOptions: libc::c_uint {
const PTRACE_O_TRACESYSGOOD = libc::PTRACE_O_TRACESYSGOOD,
const PTRACE_O_TRACEFORK = libc::PTRACE_O_TRACEFORK,
const PTRACE_O_TRACEVFORK = libc::PTRACE_O_TRACEVFORK,
const PTRACE_O_TRACECLONE = libc::PTRACE_O_TRACECLONE,
const PTRACE_O_TRACEEXEC = libc::PTRACE_O_TRACEEXEC,
const PTRACE_O_TRACEVFORKDONE = libc::PTRACE_O_TRACEVFORKDONE,
const PTRACE_O_TRACEEXIT = libc::PTRACE_O_TRACEEXIT,
const PTRACE_O_TRACESECCOMP = libc::PTRACE_O_TRACESECCOMP,
}
}
}

mod ffi {
Expand All @@ -75,15 +96,15 @@ pub fn ptrace(request: ptrace::PtraceRequest, pid: pid_t, addr: *mut c_void, dat
use self::ptrace::*;

match request {
PTRACE_PEEKTEXT | PTRACE_PEEKDATA | PTRACE_PEEKUSER => ptrace_peek(request, pid, addr, data),
PtraceRequest::PTRACE_PEEKTEXT | PtraceRequest::PTRACE_PEEKDATA | PtraceRequest::PTRACE_PEEKUSER => ptrace_peek(request, pid, addr, data),
_ => ptrace_other(request, pid, addr, data)
}
}

fn ptrace_peek(request: ptrace::PtraceRequest, pid: pid_t, addr: *mut c_void, data: *mut c_void) -> Result<c_long> {
let ret = unsafe {
Errno::clear();
ffi::ptrace(request, pid, addr, data)
ffi::ptrace(request as c_int, pid, addr, data)
};
match Errno::result(ret) {
Ok(..) | Err(Error::Sys(Errno::UnknownErrno)) => Ok(ret),
Expand All @@ -92,13 +113,13 @@ fn ptrace_peek(request: ptrace::PtraceRequest, pid: pid_t, addr: *mut c_void, da
}

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)
Errno::result(unsafe { ffi::ptrace(request as c_int, pid, addr, data) }).map(|_| 0)
}

/// Set options, as with `ptrace(PTRACE_SETOPTIONS,...)`.
pub fn ptrace_setoptions(pid: pid_t, options: ptrace::PtraceOptions) -> Result<()> {
use self::ptrace::*;
use std::ptr;

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