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, &regs);
+            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, &regs);
+                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