Re: [PATCH v2 3/3] libdtrace: match BEGIN/END PID in the tracer's own PID namespace
Jacob Carlborg <[email protected]>
| Newsgroups | dev.linux.lists.dtrace |
|---|---|
| Message-ID | <[email protected]> |
Ok, sounds good. Thanks. -- /Jacob Carlborg > On 5 Aug 2026, at 19:12, Kris Van Hees <[email protected]> wrote: > > 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) >> >> >>