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

Use latest version of nix #141

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ syntect = {version = "4.4.0", optional = true}
# Dependencies specific to macOS & Linux
[target.'cfg(unix)'.dependencies]
memmap = "0.7.0"
nix = "0.17.0"
nix = { git = "https://github.com/nix-rust/nix", branch = "master" }
libproc = "0.7.2"
libc = "0.2.72"

Expand Down
14 changes: 8 additions & 6 deletions examples/gui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,12 +388,14 @@ mod example {
let mut breakpoint_inst = pause_inst.to_ne_bytes();
// int3; nop; ...
breakpoint_inst[0] = 0xcc;
nix::sys::ptrace::write(
context.remote()?.pid(),
breakpoint_addr as *mut _,
libc::c_ulong::from_ne_bytes(breakpoint_inst) as *mut _,
)
.unwrap();
unsafe {
nix::sys::ptrace::write(
context.remote()?.pid(),
breakpoint_addr as *mut _,
libc::c_ulong::from_ne_bytes(breakpoint_inst) as *mut _,
)
.unwrap();
}

Ok(())
}
Expand Down
90 changes: 35 additions & 55 deletions src/target/linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ use crate::target::{
unix::{self, UnixTarget},
};
use crate::CrabResult;
use nix::libc::user_regs_struct;
use nix::sys::ptrace;
use nix::sys::signal;
use nix::sys::wait::{waitpid, WaitStatus};
use nix::unistd::{getpid, Pid};
use procfs::process::{Process, Task};
Expand Down Expand Up @@ -61,18 +63,18 @@ impl LinuxThread {

impl<Regs> Thread<Regs> for LinuxThread
where
Regs: Registers + From<libc::user_regs_struct> + Into<libc::user_regs_struct>,
Regs: Registers + From<user_regs_struct> + Into<user_regs_struct>,
{
type ThreadId = i32;

fn read_regs(&self) -> CrabResult<Regs> {
let regs = nix::sys::ptrace::getregs(Pid::from_raw(self.task.tid))?;
let regs = ptrace::getregs(Pid::from_raw(self.task.tid))?;
Ok(Regs::from(regs))
}

fn write_regs(&self, regs: Regs) -> CrabResult<()> {
let regs = regs.into();
nix::sys::ptrace::setregs(Pid::from_raw(self.task.tid), regs)?;
ptrace::setregs(Pid::from_raw(self.task.tid), regs)?;
Ok(())
}

Expand Down Expand Up @@ -126,7 +128,7 @@ impl UnixTarget for LinuxTarget {
let status = waitpid(self.pid(), None)?;

// We may have hit a user defined breakpoint
if let WaitStatus::Stopped(_, nix::sys::signal::Signal::SIGTRAP) = status {
if let WaitStatus::Stopped(_, signal::Signal::SIGTRAP) = status {
let regs = self.main_thread()?.read_regs()?;

if let Some(bp) = self
Expand Down Expand Up @@ -198,7 +200,7 @@ impl LinuxTarget {
}

/// Launches a new debuggee process
pub fn launch(cmd: Command) -> CrabResult<(LinuxTarget, nix::sys::wait::WaitStatus)> {
pub fn launch(cmd: Command) -> CrabResult<(LinuxTarget, WaitStatus)> {
let (pid, status) = unix::launch(cmd)?;
let target = LinuxTarget::from_debuggee_pid(pid);
target.kill_on_exit()?;
Expand Down Expand Up @@ -269,23 +271,27 @@ impl LinuxTarget {

// Write syscall instruction
// FIXME search for an existing syscall instruction once instead
let old_inst = nix::sys::ptrace::read(self.pid(), new_regs.ip() as *mut _)?;
nix::sys::ptrace::write(
self.pid(),
new_regs.ip() as *mut _,
0x050f/*x86_64 syscall*/ as *mut _,
)?;
let old_inst = ptrace::read(self.pid(), new_regs.ip() as *mut _)?;
unsafe {
ptrace::write(
self.pid(),
new_regs.ip() as *mut _,
0x050f/*x86_64 syscall*/ as *mut _,
)?;
}

// Perform syscall
nix::sys::ptrace::step(self.pid(), None)?;
nix::sys::wait::waitpid(self.pid(), None)?;
ptrace::step(self.pid(), None)?;
waitpid(self.pid(), None)?;

// Read return value
let regs = self.read_regs()?;
let res = regs.reg_for_dwarf(X86_64::RAX);

// Restore old code and registers
nix::sys::ptrace::write(self.pid(), new_regs.ip() as *mut _, old_inst as *mut _)?;
unsafe {
ptrace::write(self.pid(), new_regs.ip() as *mut _, old_inst as *mut _)?;
}
self.main_thread()?.write_regs(orig_regs)?;

Ok(res.unwrap())
Expand Down Expand Up @@ -344,7 +350,7 @@ impl LinuxTarget {

/// Kill debuggee when debugger exits.
fn kill_on_exit(&self) -> CrabResult<()> {
nix::sys::ptrace::setoptions(self.pid, nix::sys::ptrace::Options::PTRACE_O_EXITKILL)?;
ptrace::setoptions(self.pid, ptrace::Options::PTRACE_O_EXITKILL)?;
Ok(())
}

Expand Down Expand Up @@ -382,7 +388,8 @@ impl LinuxTarget {
let bit_mask = HardwareBreakpoint::bit_mask(index);

let mut dr7: u64 =
self.ptrace_peekuser((*DEBUG_REG_OFFSET + 7 * 8) as *mut libc::c_void)? as u64;
ptrace::read_user(self.pid, (*DEBUG_REG_OFFSET + 7 * 8) as *mut libc::c_void)?
as u64;

// Check if hardware watchpoint is already used
if dr7 & (1 << (2 * index)) != 0 {
Expand All @@ -392,23 +399,18 @@ impl LinuxTarget {

dr7 = (dr7 & !bit_mask) | (enable_bit | rw_bits | size_bits);

#[allow(deprecated)]
unsafe {
// Have to use deprecated function because of no alternative for PTRACE_POKEUSER
ptrace::ptrace(
ptrace::Request::PTRACE_POKEUSER,
ptrace::write_user(
self.pid,
(*DEBUG_REG_OFFSET + index * 8) as *mut libc::c_void,
breakpoint.addr as *mut libc::c_void,
)?;
ptrace::ptrace(
ptrace::Request::PTRACE_POKEUSER,
ptrace::write_user(
self.pid,
(*DEBUG_REG_OFFSET + 7 * 8) as *mut libc::c_void,
dr7 as *mut libc::c_void,
)?;
ptrace::ptrace(
ptrace::Request::PTRACE_POKEUSER,
ptrace::write_user(
self.pid,
(*DEBUG_REG_OFFSET + 6 * 8) as *mut libc::c_void,
ptr::null_mut(),
Expand All @@ -431,27 +433,25 @@ impl LinuxTarget {
}

let mut dr7 =
self.ptrace_peekuser((*DEBUG_REG_OFFSET + 7 * 8) as *mut libc::c_void)? as u64;
ptrace::read_user(self.pid, (*DEBUG_REG_OFFSET + 7 * 8) as *mut libc::c_void)?
as u64;
let mut dr6 =
self.ptrace_peekuser((*DEBUG_REG_OFFSET + 6 * 8) as *mut libc::c_void)? as u64;
ptrace::read_user(self.pid, (*DEBUG_REG_OFFSET + 6 * 8) as *mut libc::c_void)?
as u64;

let dr7_bit_mask: u64 = HardwareBreakpoint::bit_mask(index);
dr7 &= !dr7_bit_mask;

let dr6_bit_mask: u64 = 1 << index;
dr6 &= !dr6_bit_mask as u64;

#[allow(deprecated)]
unsafe {
// Have to use deprecated function because of no alternative for PTRACE_POKEUSER
ptrace::ptrace(
ptrace::Request::PTRACE_POKEUSER,
ptrace::write_user(
self.pid,
(*DEBUG_REG_OFFSET + 7 * 8) as *mut libc::c_void,
dr7 as *mut libc::c_void,
)?;
ptrace::ptrace(
ptrace::Request::PTRACE_POKEUSER,
ptrace::write_user(
self.pid,
(*DEBUG_REG_OFFSET + 6 * 8) as *mut libc::c_void,
dr6 as *mut libc::c_void,
Expand All @@ -478,17 +478,15 @@ impl LinuxTarget {
pub fn is_hardware_breakpoint_triggered(&self) -> CrabResult<Option<usize>> {
#[cfg(target_arch = "x86_64")]
{
let mut dr7 = self.ptrace_peekuser((*DEBUG_REG_OFFSET + 6 * 8) as *mut libc::c_void)?;
let mut dr7 =
ptrace::read_user(self.pid, (*DEBUG_REG_OFFSET + 6 * 8) as *mut libc::c_void)?;

for i in 0..SUPPORTED_HARDWARE_BREAKPOINTS {
if dr7 & (1 << i) != 0 && self.hardware_breakpoints[i].is_some() {
// Clear bit for this breakpoint
dr7 &= !(1 << i);
// Have to use deprecated function because of no alternative for PTRACE_POKEUSER
#[allow(deprecated)]
unsafe {
ptrace::ptrace(
ptrace::Request::PTRACE_POKEUSER,
ptrace::write_user(
self.pid,
(*DEBUG_REG_OFFSET + 6 * 8) as *mut libc::c_void,
dr7 as *mut libc::c_void,
Expand Down Expand Up @@ -551,24 +549,6 @@ impl LinuxTarget {
bp.disable().map_err(|e| e.into())
}

// Temporary function until ptrace_peekuser is fixed in nix crate
#[cfg(target_arch = "x86_64")]
fn ptrace_peekuser(&self, addr: *mut libc::c_void) -> CrabResult<libc::c_long> {
let ret = unsafe {
nix::errno::Errno::clear();
libc::ptrace(
ptrace::Request::PTRACE_PEEKUSER as libc::c_uint,
libc::pid_t::from(self.pid),
addr,
std::ptr::null_mut() as *mut libc::c_void,
)
};
match nix::errno::Errno::result(ret) {
Ok(..) | Err(nix::Error::Sys(nix::errno::Errno::UnknownErrno)) => Ok(ret),
Err(err) => Err(Box::new(err)),
}
}

fn find_empty_watchpoint(&self) -> Option<usize> {
self.hardware_breakpoints.iter().position(|w| w.is_none())
}
Expand Down
8 changes: 6 additions & 2 deletions src/target/linux/software_breakpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,19 @@ impl Breakpoint {
let instr = ptrace::read(self.pid, self.addr as *mut _)?;
self.shadow = instr;
let trap_instr = (instr & !0xff) | INT3;
ptrace::write(self.pid, self.addr as *mut _, trap_instr as *mut _)?;
unsafe {
ptrace::write(self.pid, self.addr as *mut _, trap_instr as *mut _)?;
}
}
self.user_enabled.set(true);
Ok(())
}

pub fn unset(&self) -> Result<(), BreakpointError> {
if self.is_armed() {
ptrace::write(self.pid, self.addr as *mut _, self.shadow as *mut _)?;
unsafe {
ptrace::write(self.pid, self.addr as *mut _, self.shadow as *mut _)?;
}
}
Ok(())
}
Expand Down
4 changes: 2 additions & 2 deletions src/target/linux/writemem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ mod tests {
let write_var2_op: u8 = 0;
let write_array = [0u8; 4];

match fork() {
match unsafe { fork() } {
Ok(ForkResult::Child) => {
ptrace::traceme().unwrap();

Expand Down Expand Up @@ -353,7 +353,7 @@ mod tests {
(ptr as *const usize, ptr.add(mem::size_of::<usize>()))
};

match fork() {
match unsafe { fork() } {
Ok(ForkResult::Child) => {
ptrace::traceme().unwrap();

Expand Down
2 changes: 1 addition & 1 deletion src/target/registers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ pub use x86_64::Registers as RegistersX86_64;
mod x86_64 {
use gimli::Register;
// This struct is available only on Linux.
use libc::user_regs_struct;
use nix::libc::user_regs_struct;

#[derive(Copy, Clone, Debug)]
pub struct Registers {
Expand Down
4 changes: 2 additions & 2 deletions tests/attach_readmem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ fn attach_readmem() -> CrabResult<()> {
.get_var_address("STATICVAR")?
.expect("Expected static var has not been found in the target binary");

match fork()? {
match unsafe { fork()? } {
ForkResult::Parent { child, .. } => {
use std::{thread, time};
thread::sleep(time::Duration::from_millis(50));
Expand Down Expand Up @@ -55,7 +55,7 @@ fn attach_readmem() -> CrabResult<()> {
}
ForkResult::Child => {
let path = CString::new(BIN_PATH)?;
execv(&path, &[])?;
execv::<CString>(&path, &[])?;

// execv replaces the process image, so this place in code will not be reached.
unreachable!();
Expand Down
3 changes: 2 additions & 1 deletion tests/readregs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ static BIN_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/testees/hell
fn read_regs() -> headcrab::CrabResult<()> {
use gimli::X86_64;
use headcrab::target::Registers;
use nix::libc::user_regs_struct;

test_utils::ensure_testees();

Expand All @@ -34,7 +35,7 @@ fn read_regs() -> headcrab::CrabResult<()> {
assert_eq!(regs.reg_for_dwarf(X86_64::RDI).unwrap(), 0);

// https://github.com/torvalds/linux/blob/f359287765c04711ff54fbd11645271d8e5ff763/arch/x86/entry/syscalls/syscall_64.tbl#L70
let user_regs: libc::user_regs_struct = regs.into();
let user_regs: user_regs_struct = regs.into();

const X86_64_SYSCALL_EXECVE: u64 = 59;
assert_eq!(user_regs.orig_rax, X86_64_SYSCALL_EXECVE);
Expand Down
14 changes: 8 additions & 6 deletions tests/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,14 @@ pub fn patch_breakpoint(target: &LinuxTarget, debuginfo: &RelocatedDwarf) {
let mut breakpoint_inst = pause_inst.to_ne_bytes();
// int3; nop; ...
breakpoint_inst[0] = 0xcc;
nix::sys::ptrace::write(
target.pid(),
breakpoint_addr as *mut _,
libc::c_ulong::from_ne_bytes(breakpoint_inst) as *mut _,
)
.unwrap();
unsafe {
nix::sys::ptrace::write(
target.pid(),
breakpoint_addr as *mut _,
libc::c_ulong::from_ne_bytes(breakpoint_inst) as *mut _,
)
.unwrap();
}
}

#[cfg(target_os = "linux")]
Expand Down