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

Attach to process on linux #43

Merged
merged 4 commits into from Jul 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/target/linux.rs
Expand Up @@ -28,6 +28,12 @@ impl LinuxTarget {
Ok(LinuxTarget { pid })
}

/// Attaches process as a debugee.
pub fn attach(pid: Pid) -> Result<LinuxTarget, Box<dyn std::error::Error>> {
unix::attach(pid)?;
Ok(LinuxTarget { pid })
}

/// Uses this process as a debuggee.
pub fn me() -> LinuxTarget {
LinuxTarget { pid: getpid() }
Expand Down
7 changes: 7 additions & 0 deletions src/target/unix.rs
Expand Up @@ -40,3 +40,10 @@ pub(crate) fn launch(path: &str) -> Result<Pid, Box<dyn std::error::Error>> {
}
}
}

/// Attach existing process as a debugee.
pub(crate) fn attach(pid: Pid) -> Result<(), Box<dyn std::error::Error>> {
ptrace::attach(pid)?;
let _status = waitpid(pid, None);
Ok(())
}
58 changes: 58 additions & 0 deletions tests/attach_readmem.rs
@@ -0,0 +1,58 @@
//! This is a simple test to attach to already running debugee process

use nix::unistd::{execv, fork, ForkResult};
use std::ffi::CString;

mod test_utils;

#[cfg(target_os = "linux")]
use headcrab::{symbol::Dwarf, target::LinuxTarget};

static BIN_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/testees/longer_hello");

// Ignoring because most linux distributions have attaching to a running process disabled.
// To run the test it either requires root privilages or CAP_SYS_PTRACE capability.
#[ignore]
#[cfg(target_os = "linux")]
#[test]
fn attach_readmem() -> Result<(), Box<dyn std::error::Error>> {
test_utils::ensure_testees();

let debuginfo = Dwarf::new(BIN_PATH)?;

let str_addr = debuginfo
.get_var_address("STATICVAR")
.expect("Expected static var has not been found in the target binary");

match fork()? {
ForkResult::Parent { child, .. } => {
use std::{thread, time};
thread::sleep(time::Duration::from_millis(50));

let target = LinuxTarget::attach(child)?;
JJendryka marked this conversation as resolved.
Show resolved Hide resolved

// Read pointer
let mut ptr_addr: usize = 0;
unsafe {
target.read().read(&mut ptr_addr, str_addr).apply()?;
}

// Read current value
let mut rval = [0u8; 13];
unsafe {
target.read().read(&mut rval, ptr_addr).apply()?;
}

assert_eq!(&rval, b"Hello, world!");

Ok(())
}
ForkResult::Child => {
let path = CString::new(BIN_PATH)?;
execv(&path, &[])?;

// execv replaces the process image, so this place in code will not be reached.
unreachable!();
}
}
}
1 change: 1 addition & 0 deletions tests/testees/.gitignore
@@ -1 +1,2 @@
/hello
/longer_hello
9 changes: 9 additions & 0 deletions tests/testees/longer_hello.rs
@@ -0,0 +1,9 @@
static STATICVAR: &str = "Hello, world!\n";

pub fn main() {

use std::{thread, time};
thread::sleep(time::Duration::from_millis(100));

println!("{}", STATICVAR);
}