Skip to content

Commit 2dce917

Browse files
nickalcockkvanhees
authored andcommitted
libproc: guard against Puntrace() of terminated processes
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: #0 0x00007f55dbe8035f in dt_list_delete (dlp=0x7f55d0001428, existing=0x0) at libcommon/dt_list.c:81 #1 0x00007f55dbe8239b in Ppop_state (P=0x7f55d0001410) at libproc/Pcontrol.c:1280 #2 0x00007f55dbe827fb in Puntrace (P=0x7f55d0001410, leave_stopped=0) at libproc/Pcontrol.c:1456 #3 0x00007f55dbe8bffd in rd_ldso_consistent_end (rd=0x7f55d00046e0) at libproc/rtld_db.c:1113 #4 0x00007f55dbe8d5d8 in rd_loadobj_iter (rd=0x7f55d00046e0, fun=0x7f55dbe863cb <map_iter>, state=0x7f55d0001410) at libproc/rtld_db.c:1934 #5 0x00007f55dbe876d3 in Pupdate_lmids (P=0x7f55d0001410) at libproc/Psymtab.c:813 #6 0x00007f55dbe87827 in Paddr_to_map (P=0x7f55d0001410, addr=4199075) at libproc/Psymtab.c:883 #7 0x00007f55dbe5354c in dt_pid_create_usdt_probes_proc (dtp=0x1a47ebb0, dpr=0x29234ea0, pdp=0x7fff392bb090, pcb=0x7fff392bb170) at libdtrace/dt_pid.c:987 #8 0x00007f55dbe54056 in dt_pid_create_usdt_probes (pdp=0x2ac157c0, dtp=0x1a47ebb0, pcb=0x7fff392bb170) at libdtrace/dt_pid.c:1265 #9 0x00007f55dbe71ce2 in discover (dtp=0x1a47ebb0) at libdtrace/dt_prov_uprobe.c:520 #10 0x00007f55dbe747a2 in dt_provider_discover (dtp=0x1a47ebb0) at libdtrace/dt_provider.c:183 #11 0x00007f55dbe7c1b1 in dtrace_work (dtp=0x1a47ebb0, fp=0x7f55dbcfc780 <_IO_2_1_stdout_>, pfunc=0x404211 <chew>, rfunc=0x40419e <chewrec>, arg=0x0) at libdtrace/dt_work.c:377 #12 0x00000000004066d5 in main (argc=11, argv=0x7fff392bb7b8) at cmd/dtrace.c:1556 (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 <[email protected]> Reviewed-by: Kris Van Hees <[email protected]>
1 parent d9021b0 commit 2dce917

File tree

1 file changed

+11
-1
lines changed

1 file changed

+11
-1
lines changed

libproc/Pcontrol.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1455,12 +1455,22 @@ Puntrace(struct ps_prochandle *P, int leave_stopped)
14551455
int prev_state;
14561456

14571457
/*
1458-
* Protect against unbalanced Ptrace()/Puntrace().
1458+
* Protect against unbalanced Ptrace()/Puntrace() and already-
1459+
* terminated processes; operations interrupted by process termination
1460+
* might reasonably do a Puntrace() to balance out a previous Ptrace(),
1461+
* but everything is freed and we just want to drop out after balancing
1462+
* the ptrace() count.
14591463
*/
14601464
if ((!P->ptraced) || (P->ptrace_count == 0))
14611465
return;
14621466

14631467
P->ptrace_count--;
1468+
1469+
if (P->released) {
1470+
_dprintf("%i: Puntrace(): early return, process is released\n", P->pid);
1471+
return;
1472+
}
1473+
14641474
prev_state = Ppop_state(P);
14651475

14661476
/*

0 commit comments

Comments
 (0)