LinuxProcessList_recurseProcTree: open dirfd first

A process can die between reading the directory listing and opening the
directory FD (if HAVE_OPENAT) or /proc files (otherwise) for reading the
process data. This race would cause LinuxProcessList_recurseProcTree to
remove it from the list immediately, which is unexpected in the
"highlight dying processes" mode and can break the tree structure.
This patch closes this race in the HAVE_OPENAT case by only accessing
the process entry after the directory FD has been opened.
This commit is contained in:
Denis Lisov 2022-02-14 00:32:28 +03:00 committed by BenBE
parent e08eec813c
commit e07fce7014
1 changed files with 9 additions and 9 deletions

View File

@ -1446,6 +1446,15 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_
if (parent && pid == parent->pid) if (parent && pid == parent->pid)
continue; continue;
#ifdef HAVE_OPENAT
int procFd = openat(dirFd, entry->d_name, O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
if (procFd < 0)
continue;
#else
char procFd[4096];
xSnprintf(procFd, sizeof(procFd), "%s/%s", dirFd, entry->d_name);
#endif
bool preExisting; bool preExisting;
Process* proc = ProcessList_getProcess(pl, pid, &preExisting, LinuxProcess_new); Process* proc = ProcessList_getProcess(pl, pid, &preExisting, LinuxProcess_new);
LinuxProcess* lp = (LinuxProcess*) proc; LinuxProcess* lp = (LinuxProcess*) proc;
@ -1453,15 +1462,6 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_
proc->tgid = parent ? parent->pid : pid; proc->tgid = parent ? parent->pid : pid;
proc->isUserlandThread = proc->pid != proc->tgid; proc->isUserlandThread = proc->pid != proc->tgid;
#ifdef HAVE_OPENAT
int procFd = openat(dirFd, entry->d_name, O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
if (procFd < 0)
goto errorReadingProcess;
#else
char procFd[4096];
xSnprintf(procFd, sizeof(procFd), "%s/%s", dirFd, entry->d_name);
#endif
LinuxProcessList_recurseProcTree(this, procFd, "task", proc, period); LinuxProcessList_recurseProcTree(this, procFd, "task", proc, period);
/* /*