From 775d909585058398fddc4f27fc8d32a7fa054aa3 Mon Sep 17 00:00:00 2001 From: Elnath Date: Fri, 18 Apr 2025 19:01:26 +0200 Subject: [PATCH] ptrace used to single-step child program --- src/child.rs | 15 +++++++++++++ src/main.rs | 59 ++++++++++++++++++++++++++++++++-------------------- 2 files changed, 52 insertions(+), 22 deletions(-) create mode 100644 src/child.rs diff --git a/src/child.rs b/src/child.rs new file mode 100644 index 0000000..6413521 --- /dev/null +++ b/src/child.rs @@ -0,0 +1,15 @@ +use nix::libc; +use nix::sys::ptrace::traceme; +use nix::unistd::execv; +use std::ffi::CString; + +pub fn starti(child_exec_path: CString) -> ! { + // ⚠️ There is a limited amount of things that can be done here, see fork's safety + match traceme() { + Ok(_) => { + execv(&child_exec_path, &[&child_exec_path]).unwrap(); + unreachable!(); + } + Err(errno) => unsafe { libc::exit(errno as i32) }, + } +} diff --git a/src/main.rs b/src/main.rs index 5d8c7e2..375161d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,33 +1,48 @@ -use nix::unistd::{execv, fork, ForkResult}; +mod child; + +use nix::sys::ptrace::*; +use nix::sys::wait::waitpid; +use nix::unistd::{ForkResult, fork}; use std::ffi::CString; use std::process::ExitCode; -use nix::sys::wait::{waitid, WaitPidFlag, WaitStatus}; fn main() -> ExitCode { let child_exec_path = CString::new(env!("TEST_PROG_PATH")).unwrap(); - match unsafe{fork()} { - Ok(ForkResult::Child) => { - // ⚠️ There is a limited amount of things that can be done here, see fork's safety - execv(&child_exec_path, &[&child_exec_path]).unwrap(); - unreachable!(); - } + match unsafe { fork() } { + Ok(ForkResult::Child) => child::starti(child_exec_path), Ok(ForkResult::Parent { child: child_pid }) => { println!("✔️ Started child {child_pid}"); - println!("⏳️ Waiting for child to exit..."); - use nix::sys::wait::Id::Pid; - match waitid(Pid(child_pid), WaitPidFlag::WEXITED) { - Err(e) => { - println!("❌ Wait failed: {e}"); - ExitCode::FAILURE - } - Ok(WaitStatus::Exited(_pid, exit_code)) => { - println!("👋 child exited with code {exit_code}"); - ExitCode::SUCCESS - } - Ok(status) => { - println!("⚠️ Unexpected status from wait! {status:#?}"); - ExitCode::FAILURE + println!("⚙️ Waiting for child signals..."); + + loop { + use nix::sys::signal::Signal::*; + use nix::sys::wait::WaitStatus::*; + match waitpid(child_pid, None) { + Err(e) => { + println!("❌ Wait failed: {e}"); + return ExitCode::FAILURE; + } + Ok(status) => match status { + Exited(_pid, exit_code) => { + println!("👋 Child exited with code {exit_code}"); + return ExitCode::SUCCESS; + } + Signaled(_, signal, _) => match signal { + SIGKILL => { + println!("💀 Child killed by SIGKILL"); + return ExitCode::SUCCESS; + } + s => println!("💡 Child received signal {s:?}"), + }, + Stopped(_pid, _signal) => { + println!("⚙️ Single-stepping child"); + step(child_pid, None).unwrap() + } + status => { + println!("⚠️ Other (unexpected) wait status: {status:?}"); + } + }, } } }