From ed1536d60fac61f0230ad0a5f185c69e3682c863 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Fri, 19 Jul 2019 21:55:17 +0200 Subject: [PATCH] WIP(ptrace): Test event system --- Cargo.lock | 4 +-- Cargo.toml | 1 + src/main.rs | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cc93e45..eb24363 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -206,7 +206,7 @@ dependencies = [ [[package]] name = "redox_syscall" version = "0.1.56" -source = "git+https://gitlab.redox-os.org/jD91mZM2/syscall.git?branch=ptrace#49dd22260bd8bada8b835d12ee8e460a5a1c4af4" +source = "git+https://gitlab.redox-os.org/jD91mZM2/syscall.git?branch=ptrace#eddcb80eb7c2d43dedf0ba2ee514b54b0b8fafc7" [[package]] name = "rustc-serialize" @@ -238,7 +238,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "strace" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/strace-redox#e64d9fb900c825e6f370da7d4bef89f10adff475" +source = "git+https://gitlab.redox-os.org/redox-os/strace-redox#b5740938279dbc8334e361d3a8bfc9a4ca64c9ce" dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/jD91mZM2/syscall.git?branch=ptrace)", diff --git a/Cargo.toml b/Cargo.toml index 55df79d..b34d235 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" [dependencies] x86 = "0.7" +# redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git" } redox_syscall = { git = "https://gitlab.redox-os.org/jD91mZM2/syscall.git", branch = "ptrace" } # redox_syscall = { path = "/home/user/redox-nix/redox/kernel/syscall" } strace = { git = "https://gitlab.redox-os.org/redox-os/strace-redox" } diff --git a/src/main.rs b/src/main.rs index d89f480..ecd326f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -56,6 +56,7 @@ fn page_fault_test() -> Result<(), String> { pub fn ptrace() -> Result<(), String> { use std::{ fs::File, + io, mem, os::unix::io::{AsRawFd, FromRawFd, RawFd} }; @@ -98,12 +99,39 @@ pub fn ptrace() -> Result<(), String> { fsqrt add rsp, 8 // pop 1 item, ignore value + // Make sure event is raised when child forks + mov rax, 120 // SYS_CLONE + xor rdi, rdi + syscall + test rax, rax + je .exit + + // Wait for child process, to make sure an ignored process is continued + mov rdi, rax + mov rax, 7 + push 0 + mov rsi, rsp + add rsp, 8 + xor rdx, rdx + syscall + + // Another fork attempt, but test what happens when not ignored + mov rax, 120 // SYS_CLONE + xor rdi, rdi + syscall + test rax, rax + je .exit + // Test behavior if tracer aborts a breakpoint before it's reached call wait_for_a_while mov rax, 158 // SYS_YIELD syscall + mov rax, 20 // GETPID + syscall + + mov rdi, rax mov rax, 37 // SYS_KILL mov rsi, 19 // SIGSTOP syscall @@ -111,20 +139,22 @@ pub fn ptrace() -> Result<(), String> { // Test nonblock & sysemu call wait_for_a_while + .exit: mov rax, 20 // GETPID syscall mov rdi, rax mov rax, 1 // SYS_EXIT syscall + ud2 // Without a jump, this code is unreachable. Therefore function definitions go here. wait_for_a_while: mov rax, 4294967295 - .loop: + .wait_for_a_while_loop: sub rax, 1 - jne .loop + jne .wait_for_a_while_loop ret " : : : : "intel", "volatile" @@ -202,6 +232,36 @@ pub fn ptrace() -> Result<(), String> { assert_eq!(fs, [f, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]); assert!((f - 5.65685424949238).abs() < std::f64::EPSILON); + println!("Testing fork event"); + let mut handler = e(tracer.next_event(Stop::COMPLETION))?.ok_or("Program completed without yielding fork event")?; + let events = e(handler.iter().collect::>>())?; + + assert_eq!(events.len(), 1); + match events[0] { + PtraceEvent::Clone(pid) => println!("Got clone: {}", pid), + ref e => return Err(format!("Wrong event type: {:?}", e)) + } + + println!("Testing fork event - but actually handling the fork"); + handler = e(handler.retry())?.ok_or("Program completed without yielding fork event")?; + let events = e(handler.iter().collect::>>())?; + assert_eq!(events.len(), 1); + match events[0] { + PtraceEvent::Clone(pid) => { + let mut child = e(Tracer::attach(pid))?; + println!("-> Fork attached (PID {})", pid); + + assert_eq!(e(e(child.next(Stop::SYSCALL))?.regs.get_int())?.rax, syscall::SYS_GETPID); + e(child.next(Stop::SYSCALL))?; + println!("-> Fork executed GETPID"); + + assert_eq!(e(e(child.next(Stop::SYSCALL))?.regs.get_int())?.rax, syscall::SYS_EXIT); + assert_eq!(child.next(Stop::COMPLETION).unwrap_err().raw_os_error(), Some(syscall::ESRCH)); + println!("-> Fork executed EXIT"); + }, + ref e => return Err(format!("Wrong event type: {:?}", e)) + } + // Activate nonblock let mut tracer = e(tracer.nonblocking())?; @@ -224,8 +284,12 @@ pub fn ptrace() -> Result<(), String> { println!("Tracee RAX: {}", e(tracer.regs.get_int())?.rax); } + println!("Waiting... Five times. To make sure it doesn't get stuck forever"); + for _ in 0..5 { + e(tracer.wait())?; + } + println!("Overriding GETPID call..."); - e(tracer.wait())?; let mut regs = e(tracer.regs.get_int())?; assert_eq!(regs.rax, syscall::SYS_GETPID); regs.rax = 123;