[DTrace-devel] [PATCH 4/5] libproc: guard against Puntrace() of terminated processes
Kris Van Hees
kris.van.hees at oracle.com
Sat Dec 7 04:38:49 UTC 2024
On Tue, Dec 03, 2024 at 06:09:46PM +0000, Nick Alcock wrote:
> 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 <nick.alcock at oracle.com>
Reviewed-by: Kris Van Hees <kris.van.hees 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