From f20fc10cdbc1b524b5a0e5d0396a89dd24b883a4 Mon Sep 17 00:00:00 2001 From: Nikita Baksalyar Date: Thu, 14 Apr 2022 01:33:30 +0100 Subject: [PATCH] Use latest version of nix --- Cargo.toml | 2 +- examples/gui.rs | 14 ++-- src/target/linux.rs | 90 ++++++++++--------------- src/target/linux/software_breakpoint.rs | 8 ++- src/target/linux/writemem.rs | 4 +- src/target/registers.rs | 2 +- tests/attach_readmem.rs | 4 +- tests/readregs.rs | 3 +- tests/test_utils.rs | 14 ++-- 9 files changed, 65 insertions(+), 76 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f1389f10..742be1ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/examples/gui.rs b/examples/gui.rs index 86138d66..2ad1006f 100644 --- a/examples/gui.rs +++ b/examples/gui.rs @@ -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(()) } diff --git a/src/target/linux.rs b/src/target/linux.rs index bf987a9c..0ee068a4 100644 --- a/src/target/linux.rs +++ b/src/target/linux.rs @@ -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}; @@ -61,18 +63,18 @@ impl LinuxThread { impl Thread for LinuxThread where - Regs: Registers + From + Into, + Regs: Registers + From + Into, { type ThreadId = i32; fn read_regs(&self) -> CrabResult { - 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(()) } @@ -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 @@ -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()?; @@ -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()) @@ -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(()) } @@ -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 { @@ -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(), @@ -431,9 +433,11 @@ 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; @@ -441,17 +445,13 @@ impl LinuxTarget { 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, @@ -478,17 +478,15 @@ impl LinuxTarget { pub fn is_hardware_breakpoint_triggered(&self) -> CrabResult> { #[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, @@ -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 { - 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 { self.hardware_breakpoints.iter().position(|w| w.is_none()) } diff --git a/src/target/linux/software_breakpoint.rs b/src/target/linux/software_breakpoint.rs index 129205fb..0c936336 100644 --- a/src/target/linux/software_breakpoint.rs +++ b/src/target/linux/software_breakpoint.rs @@ -47,7 +47,9 @@ 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(()) @@ -55,7 +57,9 @@ impl Breakpoint { 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(()) } diff --git a/src/target/linux/writemem.rs b/src/target/linux/writemem.rs index 13cc56da..0116d386 100644 --- a/src/target/linux/writemem.rs +++ b/src/target/linux/writemem.rs @@ -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(); @@ -353,7 +353,7 @@ mod tests { (ptr as *const usize, ptr.add(mem::size_of::())) }; - match fork() { + match unsafe { fork() } { Ok(ForkResult::Child) => { ptrace::traceme().unwrap(); diff --git a/src/target/registers.rs b/src/target/registers.rs index 24d9e9d1..e5822bfb 100644 --- a/src/target/registers.rs +++ b/src/target/registers.rs @@ -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 { diff --git a/tests/attach_readmem.rs b/tests/attach_readmem.rs index 0beb6d7d..4feac432 100644 --- a/tests/attach_readmem.rs +++ b/tests/attach_readmem.rs @@ -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)); @@ -55,7 +55,7 @@ fn attach_readmem() -> CrabResult<()> { } ForkResult::Child => { let path = CString::new(BIN_PATH)?; - execv(&path, &[])?; + execv::(&path, &[])?; // execv replaces the process image, so this place in code will not be reached. unreachable!(); diff --git a/tests/readregs.rs b/tests/readregs.rs index 6d9aa561..876e6104 100644 --- a/tests/readregs.rs +++ b/tests/readregs.rs @@ -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(); @@ -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); diff --git a/tests/test_utils.rs b/tests/test_utils.rs index f6ce8cfa..cfcc86e5 100644 --- a/tests/test_utils.rs +++ b/tests/test_utils.rs @@ -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")]