Linux: detect container process by different PID namespace

Container engines like docker and podman rely on Linux namespaces.  If
available check if the target process is inside a different PID
namespace than htop.  This check will mark sandbox'ed applications, e.g.
under bubblewrap, but not light-wight containers, like distrobox.
wilder
Christian Göttsche 2 years ago committed by cgzones
parent 76a13dbb4e
commit 22d25db467
  1. 2
      Process.h
  2. 58
      linux/LinuxProcessTable.c

@ -94,7 +94,7 @@ typedef struct Process_ {
bool isUserlandThread; bool isUserlandThread;
/* This process is running inside a container */ /* This process is running inside a container */
bool isRunningInContainer; Tristate isRunningInContainer;
/* Controlling terminal identifier of the process */ /* Controlling terminal identifier of the process */
unsigned long int tty_nr; unsigned long int tty_nr;

@ -60,6 +60,10 @@ in the source distribution for its full text.
#define PF_KTHREAD 0x00200000 #define PF_KTHREAD 0x00200000
#endif #endif
/* Inode number of the PID namespace of htop */
static ino_t rootPidNs = (ino_t)-1;
static FILE* fopenat(openat_arg_t openatArg, const char* pathname, const char* mode) { static FILE* fopenat(openat_arg_t openatArg, const char* pathname, const char* mode) {
assert(String_eq(mode, "r")); /* only currently supported mode */ assert(String_eq(mode, "r")); /* only currently supported mode */
@ -193,6 +197,17 @@ ProcessTable* ProcessTable_new(Machine* host, Hashtable* pidMatchList) {
// Test /proc/PID/smaps_rollup availability (faster to parse, Linux 4.14+) // Test /proc/PID/smaps_rollup availability (faster to parse, Linux 4.14+)
this->haveSmapsRollup = (access(PROCDIR "/self/smaps_rollup", R_OK) == 0); this->haveSmapsRollup = (access(PROCDIR "/self/smaps_rollup", R_OK) == 0);
// Read PID namespace inode number
{
struct stat sb;
int r = stat(PROCDIR "/self/ns/pid", &sb);
if (r == 0) {
rootPidNs = sb.st_ino;
} else {
rootPidNs = (ino_t)-1;
}
}
return super; return super;
} }
@ -369,6 +384,7 @@ static bool LinuxProcessTable_readStatusFile(Process* process, openat_arg_t proc
LinuxProcess* lp = (LinuxProcess*) process; LinuxProcess* lp = (LinuxProcess*) process;
unsigned long ctxt = 0; unsigned long ctxt = 0;
process->isRunningInContainer = TRI_OFF;
#ifdef HAVE_VSERVER #ifdef HAVE_VSERVER
lp->vxid = 0; lp->vxid = 0;
#endif #endif
@ -397,7 +413,7 @@ static bool LinuxProcessTable_readStatusFile(Process* process, openat_arg_t proc
} }
if (pid_ns_count > 1) if (pid_ns_count > 1)
process->isRunningInContainer = true; process->isRunningInContainer = TRI_ON;
} else if (String_startsWith(buffer, "voluntary_ctxt_switches:")) { } else if (String_startsWith(buffer, "voluntary_ctxt_switches:")) {
unsigned long vctxt; unsigned long vctxt;
@ -1461,7 +1477,7 @@ static bool LinuxProcessTable_recurseProcTree(LinuxProcessTable* this, openat_ar
Compat_openatArgClose(procFd); Compat_openatArgClose(procFd);
continue; continue;
} }
if (preExisting && hideRunningInContainer && proc->isRunningInContainer) { if (preExisting && hideRunningInContainer && proc->isRunningInContainer == TRI_ON) {
proc->super.updated = true; proc->super.updated = true;
proc->super.show = false; proc->super.show = false;
Compat_openatArgClose(procFd); Compat_openatArgClose(procFd);
@ -1525,16 +1541,6 @@ static bool LinuxProcessTable_recurseProcTree(LinuxProcessTable* this, openat_ar
if (!LinuxProcessTable_updateUser(host, proc, procFd, mainTask)) if (!LinuxProcessTable_updateUser(host, proc, procFd, mainTask))
goto errorReadingProcess; goto errorReadingProcess;
if (ss->flags & PROCESS_FLAG_LINUX_CTXT
|| hideRunningInContainer
#ifdef HAVE_VSERVER
|| ss->flags & PROCESS_FLAG_LINUX_VSERVER
#endif
) {
if (!LinuxProcessTable_readStatusFile(proc, procFd))
goto errorReadingProcess;
}
if (!preExisting) { if (!preExisting) {
#ifdef HAVE_OPENVZ #ifdef HAVE_OPENVZ
@ -1568,6 +1574,32 @@ static bool LinuxProcessTable_recurseProcTree(LinuxProcessTable* this, openat_ar
} }
} }
/* Check if the process in inside a different PID namespace. */
if (proc->isRunningInContainer == TRI_INITIAL && rootPidNs != (ino_t)-1) {
struct stat sb;
#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT)
int res = fstatat(procFd, "ns/pid", &sb, 0);
#else
char path[4096];
xSnprintf(path, sizeof(path), "%s/ns/pid", procFd);
int res = stat(path, &sb);
#endif
if (res == 0) {
proc->isRunningInContainer = (sb.st_ino != rootPidNs) ? TRI_ON : TRI_OFF;
}
}
if (ss->flags & PROCESS_FLAG_LINUX_CTXT
|| (hideRunningInContainer && proc->isRunningInContainer == TRI_INITIAL)
#ifdef HAVE_VSERVER
|| ss->flags & PROCESS_FLAG_LINUX_VSERVER
#endif
) {
proc->isRunningInContainer = TRI_OFF;
if (!LinuxProcessTable_readStatusFile(proc, procFd))
goto errorReadingProcess;
}
/* /*
* Section gathering non-critical information that is independent from * Section gathering non-critical information that is independent from
* each other. * each other.
@ -1662,7 +1694,7 @@ static bool LinuxProcessTable_recurseProcTree(LinuxProcessTable* this, openat_ar
proc->super.updated = true; proc->super.updated = true;
Compat_openatArgClose(procFd); Compat_openatArgClose(procFd);
if (hideRunningInContainer && proc->isRunningInContainer) { if (hideRunningInContainer && proc->isRunningInContainer == TRI_ON) {
proc->super.show = false; proc->super.show = false;
continue; continue;
} }

Loading…
Cancel
Save