Merge branch 'ptrace' into 'master'
ptrace tests See merge request redox-os/acid!2
This commit is contained in:
29
Cargo.lock
generated
29
Cargo.lock
generated
@@ -4,6 +4,8 @@
|
||||
name = "acid"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)",
|
||||
"strace 0.1.0 (git+https://gitlab.redox-os.org/redox-os/strace-redox)",
|
||||
"x86 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -14,7 +16,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.0.4"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@@ -27,7 +29,7 @@ name = "cloudabi"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -44,7 +46,7 @@ name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -201,6 +203,14 @@ dependencies = [
|
||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.56"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/syscall.git#8d0015be8693a81c2a4459f3c09fb47b98ff07b1"
|
||||
dependencies = [
|
||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-serialize"
|
||||
version = "0.3.24"
|
||||
@@ -228,6 +238,15 @@ name = "siphasher"
|
||||
version = "0.2.3"
|
||||
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#d7f7921f50bb03fe855f27a439d2d9c2eac45646"
|
||||
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/redox-os/syscall.git)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.6"
|
||||
@@ -261,7 +280,7 @@ dependencies = [
|
||||
|
||||
[metadata]
|
||||
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||
"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
|
||||
"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855"
|
||||
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
|
||||
"checksum csv 0.14.7 (registry+https://github.com/rust-lang/crates.io-index)" = "266c1815d7ca63a5bd86284043faf91e8c95e943e55ce05dc0ae08e952de18bc"
|
||||
@@ -284,10 +303,12 @@ 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.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)" = "<none>"
|
||||
"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"
|
||||
"checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
|
||||
"checksum strace 0.1.0 (git+https://gitlab.redox-os.org/redox-os/strace-redox)" = "<none>"
|
||||
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
name = "acid"
|
||||
version = "0.1.0"
|
||||
authors = ["Jeremy Soller <jackpot51@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
x86 = "0.7"
|
||||
redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git" }
|
||||
strace = { git = "https://gitlab.redox-os.org/redox-os/strace-redox", default-features = false }
|
||||
#strace = { path = "../../strace/source", default-features = false }
|
||||
|
||||
447
src/main.rs
447
src/main.rs
@@ -1,7 +1,9 @@
|
||||
//!Acid testing program
|
||||
#![feature(thread_local)]
|
||||
#![feature(thread_local, asm)]
|
||||
|
||||
extern crate x86;
|
||||
fn e<T, E: ToString>(error: Result<T, E>) -> Result<T, String> {
|
||||
error.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
fn create_test() -> Result<(), String> {
|
||||
use std::fs;
|
||||
@@ -51,6 +53,446 @@ fn page_fault_test() -> Result<(), String> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn ptrace() -> Result<(), String> {
|
||||
use std::{
|
||||
fs::{File, OpenOptions},
|
||||
io::{self, prelude::*},
|
||||
mem,
|
||||
os::unix::{
|
||||
fs::OpenOptionsExt,
|
||||
io::{AsRawFd, FromRawFd, RawFd},
|
||||
},
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
use strace::*;
|
||||
|
||||
let pid = e(unsafe { syscall::clone(syscall::CloneFlags::empty()) })?;
|
||||
if pid == 0 {
|
||||
extern "C" fn sighandler(_: usize) {
|
||||
unsafe {
|
||||
asm!("
|
||||
mov rax, 158 // SYS_YIELD
|
||||
syscall
|
||||
"
|
||||
: : : : "intel", "volatile");
|
||||
}
|
||||
}
|
||||
extern "C" fn sigreturn() {
|
||||
unsafe {
|
||||
asm!("
|
||||
mov rax, 119 // SYS_SIGRETURN
|
||||
syscall
|
||||
ud2
|
||||
"
|
||||
: : : : "intel", "volatile");
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
asm!("
|
||||
// Push any arguments from rust to the stack so we're
|
||||
// free to use whatever registers we want
|
||||
push $1
|
||||
push $0
|
||||
mov rbp, rsp
|
||||
|
||||
// Wait until tracer is started
|
||||
mov rax, 20 // SYS_GETPID
|
||||
syscall
|
||||
|
||||
mov rdi, rax
|
||||
|
||||
mov rax, 37 // SYS_KILL
|
||||
mov rsi, 19 // SIGSTOP
|
||||
syscall
|
||||
|
||||
// Start of body:
|
||||
|
||||
// Test basic singlestepping
|
||||
mov rax, 1
|
||||
push rax
|
||||
mov rax, 2
|
||||
push rax
|
||||
mov rax, 3
|
||||
pop rax
|
||||
pop rax
|
||||
|
||||
// Test memory access
|
||||
push 3
|
||||
push 2
|
||||
push 1
|
||||
add rsp, 8*3 // pop 3 items, ignore values
|
||||
|
||||
// Testing floating point
|
||||
push 32
|
||||
fild QWORD PTR [rsp]
|
||||
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
|
||||
xor rdx, rdx
|
||||
syscall
|
||||
add rsp, 8
|
||||
|
||||
// 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 of signals
|
||||
mov rax, 67 // SYS_SIGACTION
|
||||
mov rdi, 10 // SIGUSR1
|
||||
push 0 // sa_flags
|
||||
push 0 // sa_mask[1]
|
||||
push 0 // sa_mask[0]
|
||||
push [rbp] // sa_handler
|
||||
mov rsi, rsp
|
||||
xor rdx, rdx
|
||||
mov r10, [rbp+0x8]
|
||||
syscall
|
||||
add rsp, 8*4
|
||||
|
||||
mov rax, 20 // SYS_GETPID
|
||||
syscall
|
||||
|
||||
mov rdi, rax
|
||||
mov rax, 37 // SYS_KILL
|
||||
mov rsi, 10 // SIGUSR1
|
||||
syscall
|
||||
|
||||
// and again
|
||||
mov rax, 37 // SYS_KILL
|
||||
syscall
|
||||
// aaaaand yet again...
|
||||
mov rax, 37 // SYS_KILL
|
||||
syscall
|
||||
// test int3
|
||||
int3
|
||||
|
||||
mov rax, 200 // SYS_GETGID
|
||||
syscall
|
||||
|
||||
// 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 // SYS_GETPID
|
||||
syscall
|
||||
|
||||
mov rdi, rax
|
||||
mov rax, 37 // SYS_KILL
|
||||
mov rsi, 19 // SIGSTOP
|
||||
syscall
|
||||
|
||||
// Test nonblock & sysemu
|
||||
call wait_for_a_while
|
||||
|
||||
exit:
|
||||
mov rax, 20 // SYS_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
|
||||
wait_for_a_while_loop:
|
||||
sub rax, 1
|
||||
jne wait_for_a_while_loop
|
||||
ret
|
||||
"
|
||||
: // no outputs
|
||||
: "r"(sighandler as usize), "r"(sigreturn as usize)
|
||||
: // no clobbers
|
||||
: "intel", "volatile"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
println!("My PID: {}", e(syscall::getpid())?);
|
||||
println!("Waiting until child (pid {}) is ready to be traced...", pid);
|
||||
let mut status = 0;
|
||||
e(syscall::waitpid(pid, &mut status, syscall::WUNTRACED))?;
|
||||
|
||||
println!("The process is stopped, of course, so it shouldn't mind if we sleep here");
|
||||
thread::sleep(Duration::from_secs(1));
|
||||
|
||||
println!("Done! Attaching tracer...");
|
||||
|
||||
// Stop and attach process + get handle to registers. This also
|
||||
// tests the behavior of dup(...)
|
||||
let proc_file = e(
|
||||
OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.custom_flags(syscall::O_EXCL as i32)
|
||||
.open(format!("proc:{}/trace", pid)))?;
|
||||
let regs_file = unsafe {
|
||||
File::from_raw_fd(e(syscall::dup(proc_file.as_raw_fd() as usize, b"regs/int"))? as RawFd)
|
||||
};
|
||||
let regs_file_float = unsafe {
|
||||
File::from_raw_fd(e(syscall::dup(regs_file.as_raw_fd() as usize, b"regs/float"))? as RawFd)
|
||||
};
|
||||
|
||||
let mut tracer = Tracer {
|
||||
file: proc_file,
|
||||
regs: Registers {
|
||||
float: regs_file_float,
|
||||
int: regs_file
|
||||
},
|
||||
mem: e(Memory::attach(pid))?
|
||||
};
|
||||
|
||||
fn next(tracer: &mut Tracer, flags: Flags) -> io::Result<&mut Tracer> {
|
||||
let event = tracer.next(flags)?;
|
||||
assert_eq!(event.cause & flags, event.cause);
|
||||
Ok(tracer)
|
||||
}
|
||||
|
||||
println!("Schedule restart of process when resumed...");
|
||||
e(syscall::kill(pid, syscall::SIGCONT))?;
|
||||
|
||||
println!("But the process won't be restarted until then");
|
||||
thread::sleep(Duration::from_secs(1));
|
||||
|
||||
println!("Stepping away from the syscall instruction...");
|
||||
e(next(&mut tracer, Flags::STOP_SINGLESTEP))?;
|
||||
|
||||
println!("Testing basic singlestepping...");
|
||||
assert_eq!(e(e(next(&mut tracer, Flags::STOP_SINGLESTEP))?.regs.get_int())?.rax, 1);
|
||||
assert_eq!(e(e(next(&mut tracer, Flags::STOP_SINGLESTEP))?.regs.get_int())?.rax, 2);
|
||||
assert_eq!(e(e(next(&mut tracer, Flags::STOP_SINGLESTEP))?.regs.get_int())?.rax, 2);
|
||||
assert_eq!(e(e(next(&mut tracer, Flags::STOP_SINGLESTEP))?.regs.get_int())?.rax, 3);
|
||||
assert_eq!(e(e(next(&mut tracer, Flags::STOP_SINGLESTEP))?.regs.get_int())?.rax, 2);
|
||||
assert_eq!(e(e(next(&mut tracer, Flags::STOP_SINGLESTEP))?.regs.get_int())?.rax, 1);
|
||||
|
||||
println!("Testing memory access...");
|
||||
e(next(&mut tracer, Flags::STOP_SINGLESTEP))?;
|
||||
e(next(&mut tracer, Flags::STOP_SINGLESTEP))?;
|
||||
|
||||
e(next(&mut tracer, Flags::STOP_SINGLESTEP))?;
|
||||
let regs = e(tracer.regs.get_int())?;
|
||||
|
||||
unsafe {
|
||||
union Stack {
|
||||
words: [usize; 3],
|
||||
bytes: [u8; 3 * mem::size_of::<usize>()]
|
||||
}
|
||||
let mut out = Stack { words: [0; 3] };
|
||||
e(tracer.mem.read(regs.rsp as *const _, &mut out.bytes))?;
|
||||
assert_eq!(out.words, [1, 2, 3]);
|
||||
assert_eq!(e(tracer.mem.cursor())? as usize, regs.rsp + out.bytes.len());
|
||||
}
|
||||
|
||||
e(next(&mut tracer, Flags::STOP_SINGLESTEP))?;
|
||||
|
||||
println!("Testing floating point...");
|
||||
for _ in 0..3 {
|
||||
e(next(&mut tracer, Flags::STOP_SINGLESTEP))?;
|
||||
}
|
||||
let regs = e(tracer.regs.get_float())?;
|
||||
let f = regs.st_space_nth(0);
|
||||
let fs = regs.st_space();
|
||||
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");
|
||||
assert_eq!(e(e(next(&mut tracer, Flags::STOP_PRE_SYSCALL | Flags::EVENT_CLONE))?.regs.get_int())?.rax, syscall::SYS_CLONE);
|
||||
let mut handler = e(tracer.next_event(Flags::STOP_POST_SYSCALL | Flags::EVENT_CLONE))?;
|
||||
|
||||
let event = e(e(handler.pop_one())?.ok_or("Expected event but none occured"))?;
|
||||
let clone_pid = match event.data {
|
||||
EventData::EventClone(pid) => {
|
||||
println!("Obtained fork (PID {})", pid);
|
||||
pid
|
||||
},
|
||||
ref e => return Err(format!("Wrong event type: {:?}", e))
|
||||
};
|
||||
|
||||
let event = e(e(handler.pop_one())?.ok_or("Expected event but none occured"))?;
|
||||
assert_eq!(event.cause, Flags::STOP_POST_SYSCALL);
|
||||
assert_eq!(e(tracer.regs.get_int())?.rax, clone_pid);
|
||||
|
||||
println!("Testing fork event - but actually handling the fork");
|
||||
assert_eq!(e(e(next(&mut tracer, Flags::STOP_PRE_SYSCALL | Flags::EVENT_CLONE))?.regs.get_int())?.rax, syscall::SYS_WAITPID);
|
||||
e(next(&mut tracer, Flags::STOP_POST_SYSCALL))?;
|
||||
assert_eq!(e(e(next(&mut tracer, Flags::STOP_PRE_SYSCALL))?.regs.get_int())?.rax, syscall::SYS_CLONE);
|
||||
let mut handler = e(tracer.next_event(Flags::STOP_PRE_SYSCALL | Flags::EVENT_CLONE))?;
|
||||
|
||||
let event = e(e(handler.pop_one())?.ok_or("Expected event but none occured"))?;
|
||||
match event.data {
|
||||
EventData::EventClone(pid) => {
|
||||
let mut child = e(Tracer::attach(pid))?;
|
||||
println!("-> Fork attached (PID {})", pid);
|
||||
|
||||
assert_eq!(e(e(next(&mut child, Flags::STOP_PRE_SYSCALL))?.regs.get_int())?.rax, syscall::SYS_GETPID);
|
||||
e(child.next(Flags::STOP_POST_SYSCALL))?;
|
||||
println!("-> Fork executed GETPID");
|
||||
|
||||
assert_eq!(e(e(next(&mut child, Flags::STOP_PRE_SYSCALL))?.regs.get_int())?.rax, syscall::SYS_EXIT);
|
||||
assert_eq!(child.next(Flags::empty()).unwrap_err().raw_os_error(), Some(syscall::ESRCH));
|
||||
println!("-> Fork executed EXIT");
|
||||
},
|
||||
ref e => return Err(format!("Wrong event type: {:?}", e))
|
||||
}
|
||||
e(e(handler.pop_one())?.ok_or("Expected event but none occured"))?;
|
||||
|
||||
println!("Testing signals");
|
||||
assert_eq!(e(tracer.regs.get_int())?.rax, syscall::SYS_SIGACTION);
|
||||
e(next(&mut tracer, Flags::STOP_POST_SYSCALL))?;
|
||||
assert_eq!(e(e(next(&mut tracer, Flags::STOP_PRE_SYSCALL))?.regs.get_int())?.rax, syscall::SYS_GETPID);
|
||||
e(next(&mut tracer, Flags::STOP_POST_SYSCALL))?;
|
||||
assert_eq!(e(e(next(&mut tracer, Flags::STOP_PRE_SYSCALL))?.regs.get_int())?.rax, syscall::SYS_KILL);
|
||||
|
||||
let event = e(tracer.next(Flags::STOP_PRE_SYSCALL | Flags::STOP_SIGNAL))?;
|
||||
|
||||
assert_eq!(event.cause, Flags::STOP_SIGNAL);
|
||||
match event.data {
|
||||
EventData::StopSignal(signal, handler) => {
|
||||
assert_eq!(signal, syscall::SIGUSR1);
|
||||
assert_ne!(handler, syscall::SIG_DFL);
|
||||
assert_ne!(handler, syscall::SIG_IGN);
|
||||
},
|
||||
ref e => return Err(format!("Wrong event type: {:?}", e))
|
||||
}
|
||||
|
||||
for i in 0..2 {
|
||||
assert_eq!(e(e(next(&mut tracer, Flags::STOP_PRE_SYSCALL))?.regs.get_int())?.rax, syscall::SYS_YIELD);
|
||||
e(next(&mut tracer, Flags::STOP_POST_SYSCALL))?;
|
||||
assert_eq!(e(e(next(&mut tracer, Flags::STOP_PRE_SYSCALL))?.regs.get_int())?.rax, syscall::SYS_SIGRETURN);
|
||||
// sigreturn doesn't return
|
||||
e(next(&mut tracer, Flags::STOP_POST_SYSCALL))?; // post-syscall kill!
|
||||
|
||||
if i == 0 {
|
||||
assert_eq!(e(e(next(&mut tracer, Flags::STOP_SIGNAL))?.regs.get_int())?.rax, syscall::SYS_KILL);
|
||||
}
|
||||
}
|
||||
|
||||
println!("Test ignoring signal");
|
||||
let event = e(tracer.next(Flags::STOP_SIGNAL | Flags::STOP_POST_SYSCALL))?;
|
||||
assert_eq!(e(tracer.regs.get_int())?.rax, syscall::SYS_KILL);
|
||||
assert_eq!(event.cause, Flags::STOP_SIGNAL);
|
||||
match event.data {
|
||||
EventData::StopSignal(signal, _) => assert_eq!(signal, syscall::SIGUSR1),
|
||||
ref e => return Err(format!("Wrong event type: {:?}", e))
|
||||
}
|
||||
|
||||
println!("Test ignoring int3");
|
||||
let event = e(tracer.next(Flags::FLAG_IGNORE | Flags::STOP_BREAKPOINT))?;
|
||||
assert_eq!(event.cause, Flags::STOP_BREAKPOINT);
|
||||
assert_eq!(e(e(next(&mut tracer, Flags::FLAG_IGNORE | Flags::STOP_PRE_SYSCALL))?.regs.get_int())?.rax, syscall::SYS_GETGID);
|
||||
e(next(&mut tracer, Flags::STOP_POST_SYSCALL))?;
|
||||
|
||||
// Activate nonblock
|
||||
let mut tracer = e(tracer.nonblocking())?;
|
||||
|
||||
println!("Testing behavior of obsolete breakpoints...");
|
||||
e(tracer.next(Flags::STOP_PRE_SYSCALL | Flags::STOP_POST_SYSCALL))?;
|
||||
e(tracer.next(Flags::empty()))?;
|
||||
|
||||
// also, we're nonblocking, can't wait for next event like that
|
||||
assert_eq!(e(tracer.events())?.next().unwrap().unwrap_err().kind(), io::ErrorKind::WouldBlock);
|
||||
|
||||
println!("Tracee RAX: {}", e(tracer.regs.get_int())?.rax);
|
||||
|
||||
println!("Waiting for next signal from tracee that it's ready to be traced again...");
|
||||
e(syscall::waitpid(pid, &mut status, syscall::WUNTRACED))?;
|
||||
|
||||
println!("Preparing event scheme");
|
||||
let mut eventfd = e(File::open("event:"))?;
|
||||
e(eventfd.write(&syscall::Event {
|
||||
id: tracer.file.as_raw_fd() as usize,
|
||||
flags: syscall::EVENT_READ,
|
||||
data: 0,
|
||||
}))?;
|
||||
|
||||
println!("Setting sysemu breakpoint...");
|
||||
e(tracer.next(Flags::STOP_PRE_SYSCALL))?;
|
||||
|
||||
println!("Schedule restart of process after breakpoint is set...");
|
||||
e(syscall::kill(pid, syscall::SIGCONT))?;
|
||||
|
||||
println!("After non-blocking ptrace, execution continues as normal:");
|
||||
for _ in 0..5 {
|
||||
println!("Tracee RAX: {}", e(tracer.regs.get_int())?.rax);
|
||||
}
|
||||
|
||||
println!("Waiting using event scheme");
|
||||
let mut event = syscall::Event::default();
|
||||
e(eventfd.read(&mut event))?;
|
||||
|
||||
println!("Consuming events");
|
||||
|
||||
e(tracer.events())?.for_each(|_| ());
|
||||
|
||||
println!("Overriding GETPID call...");
|
||||
let mut regs = e(tracer.regs.get_int())?;
|
||||
assert_eq!(regs.rax, syscall::SYS_GETPID);
|
||||
regs.rax = 123;
|
||||
e(tracer.regs.set_int(®s))?;
|
||||
|
||||
let mut tracer = e(tracer.blocking())?;
|
||||
|
||||
println!("Checking exit syscall...");
|
||||
e(next(&mut tracer, Flags::STOP_PRE_SYSCALL | Flags::STOP_EXIT | Flags::FLAG_IGNORE))?;
|
||||
let regs = e(tracer.regs.get_int())?;
|
||||
assert_eq!(regs.rax, syscall::SYS_EXIT);
|
||||
assert_eq!(regs.rdi, 123);
|
||||
|
||||
println!("Checking exit breakpoint...");
|
||||
let event = e(tracer.next(Flags::STOP_POST_SYSCALL | Flags::STOP_EXIT))?;
|
||||
|
||||
assert_eq!(event.cause, Flags::STOP_EXIT);
|
||||
match event.data {
|
||||
EventData::StopExit(status) => {
|
||||
assert!(syscall::wifexited(status));
|
||||
assert_eq!(syscall::wexitstatus(status), 123);
|
||||
},
|
||||
ref e => return Err(format!("Wrong event type: {:?}", e))
|
||||
}
|
||||
|
||||
println!("Checking exit status (waitpid nohang)...");
|
||||
assert_eq!(next(&mut tracer, Flags::STOP_POST_SYSCALL | Flags::STOP_EXIT).unwrap_err().raw_os_error(), Some(syscall::ESRCH));
|
||||
|
||||
let mut status = 0;
|
||||
e(syscall::waitpid(pid, &mut status, syscall::WNOHANG))?;
|
||||
assert!(syscall::wifexited(status));
|
||||
assert_eq!(syscall::wexitstatus(status), 123);
|
||||
|
||||
println!("Trying to do illegal things...");
|
||||
for id in 0..=1_000_000 {
|
||||
let err = File::open(format!("proc:{}/regs/int", id)).map(|_| None).unwrap_or_else(|err| err.raw_os_error());
|
||||
assert!(
|
||||
err == Some(syscall::EPERM) || err == Some(syscall::ESRCH),
|
||||
"The cops ignored that I tried to illegally open PID {}: {:?}", id, err
|
||||
);
|
||||
}
|
||||
|
||||
println!("All done and tested!");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn switch_test() -> Result<(), String> {
|
||||
use std::thread;
|
||||
use x86::time::rdtscp;
|
||||
@@ -181,6 +623,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);
|
||||
|
||||
Reference in New Issue
Block a user