Re: [PATCH v2 3/3] libdtrace: match BEGIN/END PID in the tracer's own PID namespace

Kris Van Hees <[email protected]>
Newsgroups dev.linux.lists.dtrace
Message-ID <[email protected]>
Thank you for this patch.  I actually implemented the code to get the dev/ino
pair for the PID namespace in dt_vopen() so that we can store the values in
dtrace_hdl_t.  That way it is available to all places that need to retrieve
pidns-aware PID and TGID values.  I also added a function dt_cg_ns_pid_tgid()
to encapsulate the code to use the correct BPF helper based on whether we are
in the initial PID nameaspace or not, and I therefore modified your patch to
simply call that function rather than doing the work here.

I'm updating the other places in the code that need to be pidns-aware, and will
post the entire series once I am done with that.

I am also adding tests so that our testsuite going forward can ensure that
DTrace works in a PID namespace.

	Kris

On Sat, Jul 25, 2026 at 08:04:09PM +0200, Jacob Carlborg wrote:
> Without this fix, running any probe hangs with no output,
> like `dtrace -n 'BEGIN { trace("hi"); exit(0); }'`.
> 
> The issues is that the `BEGIN/END` probes are implemented as uprobes
> on DTrace's own `BEGIN_probe()/END_probe()` functions in `dt_work.c`.
> `bpf_get_current_pid_tgid()` reports the TGID in the initial PID
> namespace, which does not match `getpid()` when DTrace runs inside a
> PID namespace. Using the `--pid=host` flag when running OrbStack does
> not help, because it shares the daemon's namespace, not the kernel
> init namespace. OrbStack's own supervisor runs in a nested PID
> namespace. On bare metal `--pid=host` does reach the init namespaces
> and the bug wouldn't appear.
> 
> This fix is when DTrace is in a non-initial PID namespace and the
> kernel is at least 5.7, use `bpf_get_ns_current_pid_tgid` instead of
> `bpf_get_current_pid_tgid`. `bpf_get_ns_current_pid_tgid` is
> namespace aware.
> 
> Signed-off-by: Jacob Carlborg <[email protected]>
> ---
>  libdtrace/dt_prov_dtrace.c | 58 ++++++++++++++++++++++++++++++++++----
>  1 file changed, 53 insertions(+), 5 deletions(-)
> 
> diff --git a/libdtrace/dt_prov_dtrace.c b/libdtrace/dt_prov_dtrace.c
> index 4b788507..179ee4d6 100644
> --- a/libdtrace/dt_prov_dtrace.c
> +++ b/libdtrace/dt_prov_dtrace.c
> @@ -9,6 +9,7 @@
>  #include <assert.h>
>  #include <errno.h>
>  #include <string.h>
> +#include <sys/stat.h>
> 
>  #include <bpf_asm.h>
> 
> @@ -129,12 +130,59 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
>          * the trampoline to minimize the cost of pointless firings in other
>          * tracers, even though this means preserving the context in %r1 around
>          * the call.
> +        *
> +        * bpf_get_current_pid_tgid() reports the TGID in the initial PID
> +        * namespace, which does not match getpid() when DTrace runs inside a
> +        * PID namespace (e.g. in a container) -- so the BEGIN/END probes would
> +        * never recognise their own firing and tracing would never activate.
> +        * When we are in a non-initial PID namespace on a kernel that provides
> +        * it (5.7+), use bpf_get_ns_current_pid_tgid() with DTrace's own PID
> +        * namespace so the value is reported in the same namespace as getpid().
> +        * Otherwise fall back to bpf_get_current_pid_tgid(), leaving the
> +        * initial-namespace case (and kernels < 5.7) exactly as before.
>          */
> -       emit(dlp, BPF_MOV_REG(BPF_REG_6, BPF_REG_1));
> -       emit(dlp, BPF_CALL_HELPER(BPF_FUNC_get_current_pid_tgid));
> -       emit(dlp, BPF_ALU64_IMM(BPF_RSH, BPF_REG_0, 32));
> -       emit(dlp, BPF_BRANCH_IMM(BPF_JNE, BPF_REG_0, getpid(), pcb->pcb_fastlbl));
> -       emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_6));
> +       {
> +               struct stat     st;
> +               int             use_ns = 0;
> +               uint64_t        dev = 0, ino = 0;
> +
> +               /*
> +                * The initial PID namespace has a fixed inode number
> +                * (PROC_PID_INIT_INO, 0xEFFFFFFC).  If we are in it, getpid()
> +                * already agrees with bpf_get_current_pid_tgid() and no
> +                * namespace lookup is needed.
> +                */
> +               if (stat("/proc/self/ns/pid", &st) == 0 &&
> +                   st.st_ino != 0xEFFFFFFCULL &&
> +                   pcb->pcb_hdl->dt_kernver >= DT_VERSION_NUMBER(5, 7, 0)) {
> +                       use_ns = 1;
> +                       dev = st.st_dev;
> +                       ino = st.st_ino;
> +               }
> +
> +               emit(dlp, BPF_MOV_REG(BPF_REG_6, BPF_REG_1));
> +               if (use_ns) {
> +                       /*
> +                        * bpf_get_ns_current_pid_tgid(dev, ino, &nsinfo, sz)
> +                        * fills a struct bpf_pidns_info { u32 pid; u32 tgid; };
> +                        * the tgid is at offset 4.
> +                        */
> +                       dt_cg_xsetx(dlp, NULL, DT_LBL_NONE, BPF_REG_1, dev);
> +                       dt_cg_xsetx(dlp, NULL, DT_LBL_NONE, BPF_REG_2, ino);
> +                       emit(dlp, BPF_MOV_REG(BPF_REG_3, BPF_REG_FP));
> +                       emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, DT_TRAMP_SP_SLOT(0)));
> +                       emit(dlp, BPF_MOV_IMM(BPF_REG_4, 8));
> +                       emit(dlp, BPF_CALL_HELPER(BPF_FUNC_get_ns_current_pid_tgid));
> +                       emit(dlp, BPF_LOAD(BPF_W, BPF_REG_0, BPF_REG_FP,
> +                                          DT_TRAMP_SP_SLOT(0) + 4));
> +               } else {
> +                       emit(dlp, BPF_CALL_HELPER(BPF_FUNC_get_current_pid_tgid));
> +                       emit(dlp, BPF_ALU64_IMM(BPF_RSH, BPF_REG_0, 32));
> +               }
> +               emit(dlp, BPF_BRANCH_IMM(BPF_JNE, BPF_REG_0, getpid(),
> +                                        pcb->pcb_fastlbl));
> +               emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_6));
> +       }
> 
>         dt_cg_tramp_prologue_act(pcb, act);
> 
> --
> 2.50.1 (Apple Git-155)
> 
> 
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.