From 9c891384ea08755fe117333d3ecbbcd4cab64dbf Mon Sep 17 00:00:00 2001
From: jD91mZM2 <me@krake.one>
Date: Tue, 16 Jun 2020 13:42:04 +0200
Subject: [PATCH] Fix ptrace returning ENODEV when process exists

---
 src/ptrace.rs          | 25 +++++++++++++++++--------
 src/scheme/proc.rs     |  3 +++
 src/syscall/process.rs |  6 +++---
 3 files changed, 23 insertions(+), 11 deletions(-)

diff --git a/src/ptrace.rs b/src/ptrace.rs
index 7029d84..90ca718 100644
--- a/src/ptrace.rs
+++ b/src/ptrace.rs
@@ -112,7 +112,11 @@ impl Session {
         F: FnOnce(&Session) -> Result<T>,
     {
         let sessions = sessions();
-        let session = sessions.get(&pid).ok_or(Error::new(ENODEV))?;
+        let session = sessions.get(&pid).ok_or_else(|| {
+            println!("session doesn't exist - returning ENODEV.");
+            println!("can this ever happen?");
+            Error::new(ENODEV)
+        })?;
 
         callback(session)
     }
@@ -160,6 +164,18 @@ pub fn close_session(pid: ContextId) {
     if let Some(session) = sessions_mut().remove(&pid) {
         session.tracer.notify();
         session.tracee.notify();
+    }
+}
+
+/// Wake up the tracer to make sure it catches on that the tracee is dead. This
+/// is different from `close_session` in that it doesn't actually close the
+/// session, and instead waits for the file handle to be closed, where the
+/// session will *actually* be closed. This is partly to ensure ENOSRCH is
+/// returned rather than ENODEV (which occurs when there's no session - should
+/// never really happen).
+pub fn close_tracee(pid: ContextId) {
+    if let Some(session) = sessions().get(&pid) {
+        session.tracer.notify();
 
         let data = session.data.lock();
         proc_trigger_event(data.file_id, EVENT_READ);
@@ -250,13 +266,6 @@ pub fn wait(pid: ContextId) -> Result<()> {
         }
     }
 
-    let contexts = context::contexts();
-    let context = contexts.get(pid).ok_or(Error::new(ESRCH))?;
-    let context = context.read();
-    if let Status::Exited(_) = context.status {
-        return Err(Error::new(ESRCH));
-    }
-
     Ok(())
 }
 
diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs
index f80f166..64346ee 100644
--- a/src/scheme/proc.rs
+++ b/src/scheme/proc.rs
@@ -374,6 +374,9 @@ impl Scheme for ProcScheme {
                     ptrace::wait(handle.info.pid)?;
                 }
 
+                // Check if context exists
+                with_context(handle.info.pid, |_| Ok(()))?;
+
                 // Read events
                 let slice = unsafe {
                     slice::from_raw_parts_mut(
diff --git a/src/syscall/process.rs b/src/syscall/process.rs
index cf1737b..18de7f2 100644
--- a/src/syscall/process.rs
+++ b/src/syscall/process.rs
@@ -1065,6 +1065,8 @@ pub fn fexec(fd: FileHandle, arg_ptrs: &[[usize; 2]], var_ptrs: &[[usize; 2]]) -
 }
 
 pub fn exit(status: usize) -> ! {
+    ptrace::breakpoint_callback(PTRACE_STOP_EXIT, Some(ptrace_event!(PTRACE_STOP_EXIT, status)));
+
     {
         let context_lock = {
             let contexts = context::contexts();
@@ -1072,8 +1074,6 @@ pub fn exit(status: usize) -> ! {
             Arc::clone(&context_lock)
         };
 
-        ptrace::breakpoint_callback(PTRACE_STOP_EXIT, Some(ptrace_event!(PTRACE_STOP_EXIT, status)));
-
         let mut close_files = Vec::new();
         let pid = {
             let mut context = context_lock.write();
@@ -1152,7 +1152,7 @@ pub fn exit(status: usize) -> ! {
         }
 
         // Alert any tracers waiting of this process
-        ptrace::close_session(pid);
+        ptrace::close_tracee(pid);
 
         if pid == ContextId::from(1) {
             println!("Main kernel thread exited with status {:X}", status);
-- 
GitLab