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