From 22d25db4678b844842af516c0f2d117382f7c632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Tue, 9 Jan 2024 23:07:27 +0100 Subject: 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. --- Process.h | 2 +- linux/LinuxProcessTable.c | 58 ++++++++++++++++++++++++++++++++++++----------- 2 files changed, 46 insertions(+), 14 deletions(-) diff --git a/Process.h b/Process.h index 066c1402..848894ca 100644 --- a/Process.h +++ b/Process.h @@ -94,7 +94,7 @@ typedef struct Process_ { bool isUserlandThread; /* This process is running inside a container */ - bool isRunningInContainer; + Tristate isRunningInContainer; /* Controlling terminal identifier of the process */ unsigned long int tty_nr; diff --git a/linux/LinuxProcessTable.c b/linux/LinuxProcessTable.c index 64a0fd93..7044314e 100644 --- a/linux/LinuxProcessTable.c +++ b/linux/LinuxProcessTable.c @@ -60,6 +60,10 @@ in the source distribution for its full text. #define PF_KTHREAD 0x00200000 #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) { 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+) 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; } @@ -369,6 +384,7 @@ static bool LinuxProcessTable_readStatusFile(Process* process, openat_arg_t proc LinuxProcess* lp = (LinuxProcess*) process; unsigned long ctxt = 0; + process->isRunningInContainer = TRI_OFF; #ifdef HAVE_VSERVER lp->vxid = 0; #endif @@ -397,7 +413,7 @@ static bool LinuxProcessTable_readStatusFile(Process* process, openat_arg_t proc } if (pid_ns_count > 1) - process->isRunningInContainer = true; + process->isRunningInContainer = TRI_ON; } else if (String_startsWith(buffer, "voluntary_ctxt_switches:")) { unsigned long vctxt; @@ -1461,7 +1477,7 @@ static bool LinuxProcessTable_recurseProcTree(LinuxProcessTable* this, openat_ar Compat_openatArgClose(procFd); continue; } - if (preExisting && hideRunningInContainer && proc->isRunningInContainer) { + if (preExisting && hideRunningInContainer && proc->isRunningInContainer == TRI_ON) { proc->super.updated = true; proc->super.show = false; Compat_openatArgClose(procFd); @@ -1525,16 +1541,6 @@ static bool LinuxProcessTable_recurseProcTree(LinuxProcessTable* this, openat_ar if (!LinuxProcessTable_updateUser(host, proc, procFd, mainTask)) 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) { #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 * each other. @@ -1662,7 +1694,7 @@ static bool LinuxProcessTable_recurseProcTree(LinuxProcessTable* this, openat_ar proc->super.updated = true; Compat_openatArgClose(procFd); - if (hideRunningInContainer && proc->isRunningInContainer) { + if (hideRunningInContainer && proc->isRunningInContainer == TRI_ON) { proc->super.show = false; continue; } -- cgit v1.2.3