From b356ddc3aafb1cc5f3dead438840bcec5e91e645 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Mon, 1 Jul 2019 12:32:22 +0200 Subject: [PATCH] WIP(ptrace): Add test for singlesteps --- Cargo.lock | 7 +++++ Cargo.toml | 1 + src/main.rs | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 87 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index b6d66d6..bc6a0c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,6 +4,7 @@ name = "acid" version = "0.1.0" dependencies = [ + "redox_syscall 0.1.54 (git+https://gitlab.redox-os.org/jD91mZM2/syscall.git?branch=ptrace)", "x86 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -201,6 +202,11 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "redox_syscall" +version = "0.1.54" +source = "git+https://gitlab.redox-os.org/jD91mZM2/syscall.git?branch=ptrace#a7aff4b60d537e6f336ff7e8affe8801a92c20f0" + [[package]] name = "rustc-serialize" version = "0.3.24" @@ -284,6 +290,7 @@ dependencies = [ "checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372" "checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db" "checksum raw-cpuid 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13b844e4049605ff38fed943f5c7b2c691fad68d9d5bf074d2720554c4e48246" +"checksum redox_syscall 0.1.54 (git+https://gitlab.redox-os.org/jD91mZM2/syscall.git?branch=ptrace)" = "" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c97b18e9e53de541f11e497357d6c5eaeb39f0cb9c8734e274abe4935f6991fa" "checksum serde_json 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b5aaee47e038bf9552d30380d3973fff2593ee0a76d81ad4c581f267cdcadf36" diff --git a/Cargo.toml b/Cargo.toml index f57ab6d..bccefe0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,3 +5,4 @@ authors = ["Jeremy Soller "] [dependencies] x86 = "0.7" +redox_syscall = { git = "https://gitlab.redox-os.org/jD91mZM2/syscall.git", branch = "ptrace" } diff --git a/src/main.rs b/src/main.rs index 7e7ef7d..56aed2c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ //!Acid testing program -#![feature(thread_local)] +#![feature(thread_local, asm)] extern crate x86; @@ -51,6 +51,83 @@ fn page_fault_test() -> Result<(), String> { Ok(()) } +fn ptrace() -> Result<(), String> { + use std::{ + fs::File, + io::prelude::*, + os::{raw::c_int, unix::io::{AsRawFd, FromRawFd}} + }; + + let pid = unsafe { syscall::clone(0).map_err(|e| format!("clone failed: {}", e))? }; + if pid == 0 { + unsafe { + asm!(" + mov rax, 20 // GETPID + syscall + + mov rdi, rax + + mov rax, 37 // SYS_KILL + mov rsi, 19 // SIGSTOP + syscall + + // Start of body + mov rax, 1 + push rax + mov rax, 2 + push rax + mov rax, 3 + pop rax + pop rax + // End of body + + mov rax, 1 // SYS_EXIT + mov rdi, 0 + syscall + " + : : : : "intel", "volatile" + ); + } + } + + // Wait until child is ready to be traced + let mut status = 0; + syscall::waitpid(pid, &mut status, syscall::WUNTRACED).map_err(|e| format!("waitpid failed: {}", e))?; + + // Stop & attach process + get handle to registers + let mut proc_file = File::open(format!("proc:{}/trace", pid)).map_err(|e| format!("open failed: {}", e))?; + let mut regs_file = unsafe { + File::from_raw_fd( + syscall::dup(proc_file.as_raw_fd() as usize, b"regs/int") + .map_err(|e| format!("dup failed: {}", e))? as c_int + ) + }; + + // Schedule restart of process when resumed + syscall::kill(pid, syscall::SIGCONT).map_err(|e| format!("kill failed: {}", e))?; + + let mut next = move |op| -> Result { + proc_file.write(&[op]).map_err(|e| format!("ptrace operation failed: {}", e))?; + + let mut regs: syscall::IntRegisters = syscall::IntRegisters::default(); + regs_file.read(&mut regs).map_err(|e| format!("reading registers failed: {}", e))?; + Ok(regs) + }; + + // Step out of syscall down to the next instruction + let _ = next(syscall::PTRACE_SINGLESTEP)?; + assert_eq!(next(syscall::PTRACE_SINGLESTEP)?.rax, 1); + assert_eq!(next(syscall::PTRACE_SINGLESTEP)?.rax, 2); + assert_eq!(next(syscall::PTRACE_SINGLESTEP)?.rax, 2); + assert_eq!(next(syscall::PTRACE_SINGLESTEP)?.rax, 3); + assert_eq!(next(syscall::PTRACE_SINGLESTEP)?.rax, 2); + assert_eq!(next(syscall::PTRACE_SINGLESTEP)?.rax, 1); + + assert_eq!(next(syscall::PTRACE_SYSCALL)?.rax, syscall::SYS_EXIT); + + Ok(()) +} + fn switch_test() -> Result<(), String> { use std::thread; use x86::time::rdtscp; @@ -181,6 +258,7 @@ fn main() { let mut tests: BTreeMap<&'static str, fn() -> Result<(), String>> = BTreeMap::new(); tests.insert("create_test", create_test); tests.insert("page_fault", page_fault_test); + tests.insert("ptrace", ptrace); tests.insert("switch", switch_test); tests.insert("tcp_fin", tcp_fin_test); tests.insert("thread", thread_test);