ソースを参照

Fix ptrace after latest kernel changes

jD91mZM2 5 年 前
コミット
a1e45941bf
5 ファイル変更39 行追加23 行削除
  1. 1 1
      Cargo.lock
  2. 1 0
      Cargo.toml
  3. 5 3
      src/platform/redox/mod.rs
  4. 26 17
      src/platform/redox/ptrace.rs
  5. 6 2
      tests/ptrace.c

+ 1 - 1
Cargo.lock

@@ -163,7 +163,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 [[package]]
 name = "redox_syscall"
 version = "0.1.56"
-source = "git+https://gitlab.redox-os.org/jD91mZM2/syscall?branch=ptrace-6#a0581db1fa26da148ad6bb35975be084d1504f58"
+source = "git+https://gitlab.redox-os.org/jD91mZM2/syscall?branch=ptrace-6#51f0ef2826ef2b0369766c8f23c8069ae0a56846"
 dependencies = [
  "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]

+ 1 - 0
Cargo.toml

@@ -39,6 +39,7 @@ sc = "0.2.2"
 
 [target.'cfg(target_os = "redox")'.dependencies]
 redox_syscall = { git = "https://gitlab.redox-os.org/jD91mZM2/syscall", branch = "ptrace-6" }
+# redox_syscall = { path = "/home/user/redox-nix/redox/kernel/syscall" }
 spin = "0.4.10"
 
 [features]

+ 5 - 3
src/platform/redox/mod.rs

@@ -2,7 +2,7 @@ use core::{mem, ptr, result::Result as CoreResult, slice};
 use syscall::{
     self,
     data::{Map, Stat as redox_stat, StatVfs as redox_statvfs, TimeSpec as redox_timespec},
-    Result,
+    PtraceEvent, Result,
 };
 
 use crate::{
@@ -947,8 +947,10 @@ impl Pal for Sys {
         let mut sessions = state.sessions.lock();
         if let Ok(session) = ptrace::get_session(&mut sessions, pid) {
             if options & sys_wait::WNOHANG != sys_wait::WNOHANG {
-                let _ =
-                    (&mut &session.tracer).write(&syscall::PTRACE_FLAG_WAIT.bits().to_ne_bytes());
+                let _ = (&mut &session.tracer).write(&syscall::PTRACE_FLAG_WAIT);
+                let mut _event = PtraceEvent::default();
+                let _ = (&mut &session.tracer).read(&mut _event);
+
                 res = Some(e(inner(
                     &mut status,
                     options | sys_wait::WNOHANG | sys_wait::WUNTRACED,

+ 26 - 17
src/platform/redox/ptrace.rs

@@ -17,10 +17,11 @@ use core::mem;
 use syscall;
 
 pub struct Session {
-    pub tracer: File,
+    pub first: bool,
+    pub fpregs: File,
     pub mem: File,
     pub regs: File,
-    pub fpregs: File,
+    pub tracer: File,
 }
 pub struct State {
     pub sessions: Mutex<BTreeMap<pid_t, Session>>,
@@ -45,13 +46,17 @@ pub fn is_traceme(pid: pid_t) -> bool {
     )
     .is_ok()
 }
-pub fn get_session(sessions: &mut BTreeMap<pid_t, Session>, pid: pid_t) -> io::Result<&Session> {
+pub fn get_session(
+    sessions: &mut BTreeMap<pid_t, Session>,
+    pid: pid_t,
+) -> io::Result<&mut Session> {
     const NEW_FLAGS: c_int = fcntl::O_RDWR | fcntl::O_CLOEXEC;
 
     match sessions.entry(pid) {
         Entry::Vacant(entry) => {
             if is_traceme(pid) {
                 Ok(entry.insert(Session {
+                    first: true,
                     tracer: File::open(
                         &CString::new(format!("proc:{}/trace", pid)).unwrap(),
                         NEW_FLAGS | fcntl::O_NONBLOCK,
@@ -110,21 +115,25 @@ fn inner_ptrace(
             Sys::kill(pid, signal::SIGCONT as _);
 
             // TODO: Translate errors
-            let syscall =
-                syscall::PTRACE_STOP_PRE_SYSCALL.bits() | syscall::PTRACE_STOP_POST_SYSCALL.bits();
-            (&mut &session.tracer).write(
-                &match request {
-                    sys_ptrace::PTRACE_CONT => 0,
-                    sys_ptrace::PTRACE_SINGLESTEP => syscall::PTRACE_STOP_SINGLESTEP.bits(),
-                    sys_ptrace::PTRACE_SYSCALL => syscall,
-                    sys_ptrace::PTRACE_SYSEMU => syscall::PTRACE_FLAG_SYSEMU.bits() | syscall,
-                    sys_ptrace::PTRACE_SYSEMU_SINGLESTEP => {
-                        syscall::PTRACE_FLAG_SYSEMU.bits() | syscall::PTRACE_STOP_SINGLESTEP.bits()
-                    }
-                    _ => unreachable!("unhandled ptrace request type {}", request),
+            let syscall = syscall::PTRACE_STOP_PRE_SYSCALL | syscall::PTRACE_STOP_POST_SYSCALL;
+            (&mut &session.tracer).write(&match request {
+                sys_ptrace::PTRACE_CONT => syscall::PtraceFlags::empty(),
+                sys_ptrace::PTRACE_SINGLESTEP => syscall::PTRACE_STOP_SINGLESTEP,
+                // Skip the first post-syscall when connected
+                sys_ptrace::PTRACE_SYSCALL if session.first => syscall::PTRACE_STOP_PRE_SYSCALL,
+                sys_ptrace::PTRACE_SYSCALL => syscall,
+                // Skip the first post-syscall when connected
+                sys_ptrace::PTRACE_SYSEMU if session.first => {
+                    syscall::PTRACE_FLAG_SYSEMU | syscall::PTRACE_STOP_PRE_SYSCALL
+                }
+                sys_ptrace::PTRACE_SYSEMU => syscall::PTRACE_FLAG_SYSEMU | syscall,
+                sys_ptrace::PTRACE_SYSEMU_SINGLESTEP => {
+                    syscall::PTRACE_FLAG_SYSEMU | syscall::PTRACE_STOP_SINGLESTEP
                 }
-                .to_ne_bytes(),
-            )?;
+                _ => unreachable!("unhandled ptrace request type {}", request),
+            })?;
+
+            session.first = false;
             Ok(0)
         }
         sys_ptrace::PTRACE_GETREGS => {

+ 6 - 2
tests/ptrace.c

@@ -48,28 +48,32 @@ int main() {
 
         int status;
         while (true) {
-            // Pre-syscall:
+            puts("----- Pre-syscall -----");
             result = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
             ERROR_IF(ptrace, result, == -1);
             UNEXP_IF(ptrace, result, != 0);
+            puts("Wait...");
             result = waitpid(pid, &status, 0);
             ERROR_IF(waitpid, result, == -1);
             if (WIFEXITED(status)) { break; }
 
             struct user_regs_struct regs;
+            puts("Get regs");
             result = ptrace(PTRACE_GETREGS, pid, NULL, &regs);
             ERROR_IF(ptrace, result, == -1);
 
             if (regs.orig_rax == SYS_write || regs.orig_rax == SYS_write) {
                 regs.rdi = 2;
+                puts("Set regs");
                 result = ptrace(PTRACE_SETREGS, pid, NULL, &regs);
                 ERROR_IF(ptrace, result, == -1);
             }
 
-            // Post-syscall:
+            puts("Post-syscall");
             result = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
             ERROR_IF(ptrace, result, == -1);
             UNEXP_IF(ptrace, result, != 0);
+            puts("Wait...");
             result = waitpid(pid, &status, 0);
             ERROR_IF(waitpid, result, == -1);
             if (WIFEXITED(status)) { break; }