From 66f0ba0478b350e19f08e50a7f89b8d7545cccec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Thu, 16 May 2024 16:28:01 +0200 Subject: [PATCH] Linux: reorder /proc//status parsing When parsing an essential pid entry file like 'status' fails, we treat the process as a short-lived one and skip adding it into the process table. This should be done before the process is added, as the goto label used for error handling can free the process structure, thus causing an use-after-free scenario. Fixes: 22d25db46 ("Linux: detect container process by different PID namespace") Closes: #1455 --- linux/LinuxProcessTable.c | 53 ++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/linux/LinuxProcessTable.c b/linux/LinuxProcessTable.c index 0bf85a75..708e7047 100644 --- a/linux/LinuxProcessTable.c +++ b/linux/LinuxProcessTable.c @@ -1571,6 +1571,32 @@ static bool LinuxProcessTable_recurseProcTree(LinuxProcessTable* this, openat_ar if (!LinuxProcessTable_updateUser(host, proc, procFd, mainTask)) goto errorReadingProcess; + /* Check if the process is 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[PATH_MAX]; + 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 || ss->flags & PROCESS_FLAG_LINUX_CONTAINER) && 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; + } + if (!preExisting) { #ifdef HAVE_OPENVZ @@ -1604,32 +1630,6 @@ 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 || ss->flags & PROCESS_FLAG_LINUX_CONTAINER) && 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. @@ -1759,6 +1759,7 @@ errorReadingProcess: */ } else { /* A really short-lived process that we don't have full info about */ + assert(ProcessTable_findProcess(pt, Process_getPid(proc)) == NULL); Process_delete((Object*)proc); } }