Skip to content

Commit

Permalink
Use latest version of nix
Browse files Browse the repository at this point in the history
  • Loading branch information
nbaksalyar committed May 15, 2022
1 parent 5a420c5 commit f20fc10
Show file tree
Hide file tree
Showing 9 changed files with 65 additions and 76 deletions.
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

0 comments on commit f20fc10

Please sign in to comment.