[DTrace-devel] [PATCH 4/5] libproc: guard against Puntrace() of terminated processes

Nick Alcock nick.alcock at oracle.com
Tue Dec 3 11:36:09 UTC 2024


If processes terminate while the main dtrace thread is doing something in
libproc, the process-control thread will clean up, releasing all resources,
including cancelling all ptraces.  Unfortunately if the main thread is in
the middle of a Ptrace()-related operation at the time, it will finish off
by doing a balancing Puntrace().  This is of course now unbalanced, because
the process cleanup did all the Puntrace()s for us; it will then try to pop
a state vector that has already been freed, yielding a crash that looks like
this:

    at libproc/rtld_db.c:1934
    at libdtrace/dt_pid.c:987
    at libdtrace/dt_pid.c:1265
    rfunc=0x40419e <chewrec>, arg=0x0) at libdtrace/dt_work.c:377

(This can also kick in when DTrace erroneously considers a process dead even
though it isn't, which is actually what happened here: we fix that in a
later commit.)

Fixed by simply checking to see if the process has been Prelease()d in
Puntrace(), and returning early.  The process is released and all
Puntrace()s have already been done: there is nothing left to do.

Signed-off-by: Nick Alcock <nick.alcock at oracle.com>
---
 libproc/Pcontrol.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/libproc/Pcontrol.c b/libproc/Pcontrol.c
index a32a362eaa1fb..6a454ef86bc3b 100644
--- a/libproc/Pcontrol.c
+++ b/libproc/Pcontrol.c
@@ -1455,12 +1455,22 @@ Puntrace(struct ps_prochandle *P, int leave_stopped)
 	int prev_state;
 
 	/*
-	 * Protect against unbalanced Ptrace()/Puntrace().
+	 * Protect against unbalanced Ptrace()/Puntrace() and already-
+	 * terminated processes; operations interrupted by process termination
+	 * might reasonably do a Puntrace() to balance out a previous Ptrace(),
+	 * but everything is freed and we just want to drop out after balancing
+	 * the ptrace() count.
 	 */
 	if ((!P->ptraced) || (P->ptrace_count == 0))
 		return;
 
 	P->ptrace_count--;
+
+	if (P->released) {
+		_dprintf("%i: Puntrace(): early return, process is released\n", P->pid);
+		return;
+	}
+
 	prev_state = Ppop_state(P);
 
 	/*
-- 
2.47.1.279.g84c5f4e78e




More information about the DTrace-devel mailing list