Skip to content

Commit 3b7a794

Browse files
committed
Reliably detect forks in containers
It's possible to have a process in a PID namespace that nevertheless has tid == vtid (when the parent and nested PID counters happen to overlap). In this case, we wrongly take the non-container path while handling clone events and end up overwriting an unrelated threadinfo (one that happened to have real pid == new child's vpid). Fix by explicitly passing a flag meaning "the child process is in a nested PID namespace" from the driver.
1 parent ae93dc9 commit 3b7a794

File tree

4 files changed

+27
-2
lines changed

4 files changed

+27
-2
lines changed

driver/bpf/fillers.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1896,6 +1896,8 @@ FILLER(proc_startupdate_3, true)
18961896
kgid_t egid;
18971897
pid_t vtid;
18981898
pid_t vpid;
1899+
struct pid_namespace *pidns = bpf_task_active_pid_ns(task);
1900+
int pidns_level = _READ(pidns->level);
18991901

19001902
/*
19011903
* flags
@@ -1907,6 +1909,18 @@ FILLER(proc_startupdate_3, true)
19071909

19081910
flags = clone_flags_to_scap(flags);
19091911

1912+
if(pidns_level != 0) {
1913+
flags |= PPM_CL_CHILD_IN_PIDNS;
1914+
} else {
1915+
struct nsproxy *nsproxy = _READ(task->nsproxy);
1916+
if(nsproxy) {
1917+
struct pid_namespace *pid_ns_for_children = _READ(nsproxy->pid_ns_for_children);
1918+
if(pid_ns_for_children != pidns) {
1919+
flags |= PPM_CL_CHILD_IN_PIDNS;
1920+
}
1921+
}
1922+
}
1923+
19101924
res = bpf_val_to_ring_type(data, flags, PT_FLAGS32);
19111925
if (res != PPM_SUCCESS)
19121926
return res;

driver/ppm_events_public.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,8 @@ or GPL2.txt for full copies of the license.
163163
#define PPM_CL_CLONE_STOPPED (1 << 26)
164164
#define PPM_CL_CLONE_VFORK (1 << 27)
165165
#define PPM_CL_CLONE_NEWCGROUP (1 << 28)
166+
#define PPM_CL_CHILD_IN_PIDNS (1<<29) /* true if the thread created by clone() is *not*
167+
in the init pid namespace */
166168

167169
/*
168170
* Futex Operations

driver/ppm_fillers.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,10 @@ int f_proc_startupdate(struct event_filler_arguments *args)
931931
uint64_t euid = current->euid;
932932
uint64_t egid = current->egid;
933933
#endif
934+
int64_t in_pidns = 0;
935+
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
936+
struct pid_namespace *pidns = task_active_pid_ns(current);
937+
#endif
934938

935939
/*
936940
* flags
@@ -944,7 +948,11 @@ int f_proc_startupdate(struct event_filler_arguments *args)
944948
} else
945949
val = 0;
946950

947-
res = val_to_ring(args, (uint64_t)clone_flags_to_scap(val), 0, false, 0);
951+
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
952+
if(pidns != &init_pid_ns || current->nsproxy->pid_ns_for_children != pidns)
953+
in_pidns = PPM_CL_CHILD_IN_PIDNS;
954+
#endif
955+
res = val_to_ring(args, (uint64_t)clone_flags_to_scap(val) | in_pidns, 0, false, 0);
948956
if (unlikely(res != PPM_SUCCESS))
949957
return res;
950958

userspace/libsinsp/parsers.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -983,7 +983,8 @@ void sinsp_parser::parse_clone_exit(sinsp_evt *evt)
983983
ASSERT(false);
984984
}
985985

986-
if(tid != vtid)
986+
// the flag check should always suffice but leave the tid/vtid check for older driver versions
987+
if(flags & PPM_CL_CHILD_IN_PIDNS || tid != vtid)
987988
{
988989
in_container = true;
989990
}

0 commit comments

Comments
 (0)