From e559a3e2e51e9d52630c041f21305233bfc4cf95 Mon Sep 17 00:00:00 2001 From: jD91mZM2 <me@krake.one> Date: Fri, 5 Jul 2019 14:30:06 +0200 Subject: [PATCH] Stub for ptrace It's happening... --- src/header/mod.rs | 2 + src/header/sys_ptrace/cbindgen.toml | 7 ++++ src/header/sys_ptrace/mod.rs | 24 +++++++++++ src/header/sys_user/cbindgen.toml | 7 ++++ src/header/sys_user/mod.rs | 52 +++++++++++++++++++++++ src/lib.rs | 2 +- src/platform/linux/mod.rs | 1 + src/platform/linux/ptrace.rs | 9 ++++ src/platform/mod.rs | 2 +- src/platform/pal/mod.rs | 3 ++ src/platform/pal/ptrace.rs | 6 +++ src/platform/redox/mod.rs | 1 + src/platform/redox/ptrace.rs | 10 +++++ tests/Makefile | 1 + tests/expected/ptrace.stderr | 4 ++ tests/expected/ptrace.stdout | 1 + tests/ptrace.c | 64 +++++++++++++++++++++++++++++ 17 files changed, 194 insertions(+), 2 deletions(-) create mode 100644 src/header/sys_ptrace/cbindgen.toml create mode 100644 src/header/sys_ptrace/mod.rs create mode 100644 src/header/sys_user/cbindgen.toml create mode 100644 src/header/sys_user/mod.rs create mode 100644 src/platform/linux/ptrace.rs create mode 100644 src/platform/pal/ptrace.rs create mode 100644 src/platform/redox/ptrace.rs create mode 100644 tests/expected/ptrace.stderr create mode 100644 tests/expected/ptrace.stdout create mode 100644 tests/ptrace.c diff --git a/src/header/mod.rs b/src/header/mod.rs index e11ffb4c..25203a74 100644 --- a/src/header/mod.rs +++ b/src/header/mod.rs @@ -37,6 +37,7 @@ pub mod sys_epoll; pub mod sys_file; pub mod sys_ioctl; pub mod sys_mman; +pub mod sys_ptrace; //pub mod sys_resource; pub mod sys_select; pub mod sys_socket; @@ -45,6 +46,7 @@ pub mod sys_statvfs; pub mod sys_time; pub mod sys_timeb; //pub mod sys_times; +pub mod sys_user; pub mod _wctype; pub mod sys_uio; pub mod sys_un; diff --git a/src/header/sys_ptrace/cbindgen.toml b/src/header/sys_ptrace/cbindgen.toml new file mode 100644 index 00000000..3ecacd05 --- /dev/null +++ b/src/header/sys_ptrace/cbindgen.toml @@ -0,0 +1,7 @@ +sys_includes = [] +include_guard = "_SYS_PTRACE_H" +language = "C" +style = "Tag" + +[enum] +prefix_with_name = true diff --git a/src/header/sys_ptrace/mod.rs b/src/header/sys_ptrace/mod.rs new file mode 100644 index 00000000..b9cef5b7 --- /dev/null +++ b/src/header/sys_ptrace/mod.rs @@ -0,0 +1,24 @@ +//! ptrace compatibility layer for Redox OS + +use platform::types::*; +use platform::{Sys, PalPtrace}; + +pub const PTRACE_PEEKTEXT: c_int = 1; +pub const PTRACE_PEEKDATA: c_int = 2; +pub const PTRACE_POKETEXT: c_int = 4; +pub const PTRACE_POKEDATA: c_int = 5; +pub const PTRACE_CONT: c_int = 7; +pub const PTRACE_KILL: c_int = 8; +pub const PTRACE_SINGLESTEP: c_int = 9; +pub const PTRACE_GETREGS: c_int = 12; +pub const PTRACE_SETREGS: c_int = 13; +pub const PTRACE_GETFPREGS: c_int = 14; +pub const PTRACE_SETFPREGS: c_int = 15; +pub const PTRACE_ATTACH: c_int = 16; +pub const PTRACE_DETACH: c_int = 17; + +#[no_mangle] +pub unsafe extern "C" fn ptrace(request: c_int, mut params: ...) -> c_int { + // Musl also just grabs the arguments from the varargs... + Sys::ptrace(request, params.arg(), params.arg(), params.arg()) +} diff --git a/src/header/sys_user/cbindgen.toml b/src/header/sys_user/cbindgen.toml new file mode 100644 index 00000000..63c05e2a --- /dev/null +++ b/src/header/sys_user/cbindgen.toml @@ -0,0 +1,7 @@ +sys_includes = [] +include_guard = "_SYS_USER_H" +language = "C" +style = "Tag" + +[enum] +prefix_with_name = true diff --git a/src/header/sys_user/mod.rs b/src/header/sys_user/mod.rs new file mode 100644 index 00000000..ca14bdea --- /dev/null +++ b/src/header/sys_user/mod.rs @@ -0,0 +1,52 @@ +//! A part of the ptrace compatibility for Redox OS + +use platform::types::*; + +#[repr(C)] +pub struct user_fpregs_struct { + cwd: u16, + swd: u16, + ftw: u16, + fop: u16, + rip: u64, + rdp: u64, + mxcsr: u32, + mxcr_mask: u32, + st_space: [u32; 32], + xmm_space: [u32; 64], + padding: [u32; 24] +} + +#[repr(C)] +pub struct user_regs_struct { + r15: c_ulong, + r14: c_ulong, + r13: c_ulong, + r12: c_ulong, + rbp: c_ulong, + rbx: c_ulong, + r11: c_ulong, + r10: c_ulong, + r9: c_ulong, + r8: c_ulong, + rax: c_ulong, + rcx: c_ulong, + rdx: c_ulong, + rsi: c_ulong, + rdi: c_ulong, + orig_rax: c_ulong, + rip: c_ulong, + cs: c_ulong, + eflags: c_ulong, + rsp: c_ulong, + ss: c_ulong, + fs_base: c_ulong, + gs_base: c_ulong, + ds: c_ulong, + es: c_ulong, + fs: c_ulong, + gs: c_ulong +} + +#[no_mangle] +pub extern "C" fn _cbindgen_only_generates_structs_if_they_are_mentioned_which_is_dumb(a: user_fpregs_struct, b: user_regs_struct) {} diff --git a/src/lib.rs b/src/lib.rs index 3ea4a1f0..268c6dcc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,6 @@ #![allow(non_camel_case_types)] #![allow(non_upper_case_globals)] #![allow(unused_variables)] -#![feature(alloc)] #![feature(allocator_api)] #![feature(asm)] #![feature(c_variadic)] @@ -13,6 +12,7 @@ #![feature(core_intrinsics)] #![feature(global_asm)] // FIXME: Stable on nightly, remove once redox fork is updated +#![feature(alloc)] #![feature(iter_copied)] #![feature(lang_items)] #![feature(linkage)] diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index af4a1115..edd7be4b 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -15,6 +15,7 @@ use header::sys_utsname::utsname; use header::time::timespec; mod epoll; +mod ptrace; mod signal; mod socket; diff --git a/src/platform/linux/ptrace.rs b/src/platform/linux/ptrace.rs new file mode 100644 index 00000000..e2206ce6 --- /dev/null +++ b/src/platform/linux/ptrace.rs @@ -0,0 +1,9 @@ +use super::super::types::*; +use super::super::PalPtrace; +use super::{e, Sys}; + +impl PalPtrace for Sys { + fn ptrace(request: c_int, pid: pid_t, addr: *mut c_void, data: *mut c_void) -> c_int { + unsafe { e(syscall!(PTRACE, request, pid, addr, data)) as c_int } + } +} diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 047aee80..979899e9 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -12,7 +12,7 @@ mod allocator; #[path = "allocator/ralloc.rs"] mod allocator; -pub use self::pal::{Pal, PalEpoll, PalSignal, PalSocket}; +pub use self::pal::{Pal, PalEpoll, PalPtrace, PalSignal, PalSocket}; mod pal; diff --git a/src/platform/pal/mod.rs b/src/platform/pal/mod.rs index 8c542b3a..fde80078 100644 --- a/src/platform/pal/mod.rs +++ b/src/platform/pal/mod.rs @@ -10,6 +10,9 @@ use header::time::timespec; pub use self::epoll::PalEpoll; mod epoll; +pub use self::ptrace::PalPtrace; +mod ptrace; + pub use self::signal::PalSignal; mod signal; diff --git a/src/platform/pal/ptrace.rs b/src/platform/pal/ptrace.rs new file mode 100644 index 00000000..d26d84c0 --- /dev/null +++ b/src/platform/pal/ptrace.rs @@ -0,0 +1,6 @@ +use super::super::types::*; +use super::super::Pal; + +pub trait PalPtrace: Pal { + fn ptrace(request: c_int, pid: pid_t, addr: *mut c_void, data: *mut c_void) -> c_int; +} diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 317fbc44..9f854ef8 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -28,6 +28,7 @@ use super::{errno, Pal, Read}; mod epoll; mod extra; +mod ptrace; mod signal; mod socket; diff --git a/src/platform/redox/ptrace.rs b/src/platform/redox/ptrace.rs new file mode 100644 index 00000000..9c3c7180 --- /dev/null +++ b/src/platform/redox/ptrace.rs @@ -0,0 +1,10 @@ +use super::super::types::*; +use super::super::PalPtrace; +use super::{e, Sys}; + +impl PalPtrace for Sys { + fn ptrace(request: c_int, pid: pid_t, addr: *mut c_void, data: *mut c_void) -> c_int { + // Oh boy, this is not gonna be fun......... + unimplemented!() + } +} diff --git a/tests/Makefile b/tests/Makefile index da4d243b..388720a4 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -15,6 +15,7 @@ EXPECT_NAMES=\ libgen \ locale \ math \ + ptrace \ regex \ select \ setjmp \ diff --git a/tests/expected/ptrace.stderr b/tests/expected/ptrace.stderr new file mode 100644 index 00000000..289c82a8 --- /dev/null +++ b/tests/expected/ptrace.stderr @@ -0,0 +1,4 @@ +This is printed to STDOUT. +Or, at least, that's what I thought. +But all write(...) syscalls are actually redirected to STDERR by the tracer. +Big surprise, right! diff --git a/tests/expected/ptrace.stdout b/tests/expected/ptrace.stdout new file mode 100644 index 00000000..8cc46e62 --- /dev/null +++ b/tests/expected/ptrace.stdout @@ -0,0 +1 @@ +Child exited with status 0 diff --git a/tests/ptrace.c b/tests/ptrace.c new file mode 100644 index 00000000..6b4dc936 --- /dev/null +++ b/tests/ptrace.c @@ -0,0 +1,64 @@ +#include <signal.h> +#include <stdbool.h> +#include <stdio.h> +#include <sys/ptrace.h> +#include <sys/user.h> +#include <sys/wait.h> +#include <unistd.h> + +#include "test_helpers.h" + +int main() { + int pid = fork(); + ERROR_IF(fork, pid, == -1); + + if (pid == 0) { + int result = ptrace(PTRACE_TRACEME, 0, NULL, NULL); + ERROR_IF(ptrace, result, == -1); + UNEXP_IF(ptrace, result, != 0); + + // Alert parent: I'm ready + result = raise(SIGSTOP); + ERROR_IF(close, result, == -1); + UNEXP_IF(close, result, != 0); + + puts("This is printed to STDOUT."); + puts("Or, at least, that's what I thought."); + puts("But all write(...) syscalls are actually redirected to STDERR by the tracer."); + puts("Big surprise, right!"); + } else { + // Wait for child process to be ready + int result = waitpid(pid, NULL, 0); + ERROR_IF(close, result, == -1); + + int status; + while (true) { + // Pre-syscall: + result = ptrace(PTRACE_SYSCALL, pid, NULL, NULL); + ERROR_IF(close, result, == -1); + UNEXP_IF(close, result, != 0); + result = waitpid(pid, &status, 0); + ERROR_IF(close, result, == -1); + if (WIFEXITED(status)) { break; } + + struct user_regs_struct regs; + result = ptrace(PTRACE_GETREGS, pid, NULL, ®s); + ERROR_IF(close, result, == -1); + + if (regs.orig_rax == 1 || regs.orig_rax == 0x21000004) { // SYS_write on Redox and Linux + regs.rdi = 2; + result = ptrace(PTRACE_SETREGS, pid, NULL, ®s); + ERROR_IF(close, result, == -1); + } + + // Post-syscall: + result = ptrace(PTRACE_SYSCALL, pid, NULL, NULL); + ERROR_IF(close, result, == -1); + UNEXP_IF(close, result, != 0); + result = waitpid(pid, &status, 0); + ERROR_IF(close, result, == -1); + if (WIFEXITED(status)) { break; } + } + printf("Child exited with status %d\n", WEXITSTATUS(status)); + } +} -- GitLab