From b4d5b5cea98f557a856c89500dc169f511a2b817 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Fri, 5 May 2023 20:23:15 +0200 Subject: Linux: gather permitted capabilities via capget(2) #1211 has shown reading /proc//status might have a significant performance impact. It was started to be read by default to gather the permitted capabilities of the process. Gather permitted capabilities via the syscall capget(2) instead. cap_get_proc(3) is not used to avoid linking with -lcap. --- Process.c | 2 +- Process.h | 9 ++++++++- linux/LinuxProcessTable.c | 23 +++++++++++++++-------- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/Process.c b/Process.c index c343e77d..527fc201 100644 --- a/Process.c +++ b/Process.c @@ -736,7 +736,7 @@ void Process_writeField(const Process* this, RichString* str, RowField field) { } break; case USER: - if (this->elevated_priv) + if (this->elevated_priv == TRI_ON) attr = CRT_colors[PROCESS_PRIV]; else if (host->htopUserId != this->st_uid) attr = CRT_colors[PROCESS_SHADOW]; diff --git a/Process.h b/Process.h index 6a80bc51..066c1402 100644 --- a/Process.h +++ b/Process.h @@ -24,6 +24,13 @@ in the source distribution for its full text. #define DEFAULT_HIGHLIGHT_SECS 5 +typedef enum Tristate_ { + TRI_INITIAL = 0, + TRI_OFF = -1, + TRI_ON = 1, +} Tristate; + + /* Core process states (shared by platforms) * NOTE: The enum has an ordering that is important! * See processStateChar in process.c for ProcessSate -> letter mapping */ @@ -106,7 +113,7 @@ typedef struct Process_ { * - from file capabilities * - inherited from the ambient set */ - bool elevated_priv; + Tristate elevated_priv; /* Process runtime (in hundredth of a second) */ unsigned long long int time; diff --git a/linux/LinuxProcessTable.c b/linux/LinuxProcessTable.c index 9a5ffdb4..57f93227 100644 --- a/linux/LinuxProcessTable.c +++ b/linux/LinuxProcessTable.c @@ -20,7 +20,9 @@ in the source distribution for its full text. #include #include #include +#include #include +#include // raw syscall, no libcap // IWYU pragma: keep // IWYU pragma: no_include #include #include "Compat.h" @@ -391,14 +393,6 @@ static bool LinuxProcessTable_readStatusFile(Process* process, openat_arg_t proc if (pid_ns_count > 1) process->isRunningInContainer = true; - } else if (String_startsWith(buffer, "CapPrm:")) { - char* ptr = buffer + strlen("CapPrm:"); - while (*ptr == ' ' || *ptr == '\t') - ptr++; - - uint64_t cap_permitted = fast_strtoull_hex(&ptr, 16); - process->elevated_priv = cap_permitted != 0 && process->st_uid != 0; - } else if (String_startsWith(buffer, "voluntary_ctxt_switches:")) { unsigned long vctxt; int ok = sscanf(buffer, "voluntary_ctxt_switches:\t%lu", &vctxt); @@ -1481,6 +1475,19 @@ static bool LinuxProcessTable_recurseProcTree(LinuxProcessTable* this, openat_ar } } + /* Gather permitted capabilities (thread-specific data) for non-root process. */ + if (proc->st_uid != 0 && proc->elevated_priv != TRI_OFF) { + struct __user_cap_header_struct header = { .version = _LINUX_CAPABILITY_VERSION_3, .pid = Process_getPid(proc) }; + struct __user_cap_data_struct data; + + long res = syscall(SYS_capget, &header, &data); + if (res == 0) { + proc->elevated_priv = (data.permitted != 0) ? TRI_ON : TRI_OFF; + } else { + proc->elevated_priv = TRI_OFF; + } + } + if (ss->flags & PROCESS_FLAG_LINUX_CGROUP) LinuxProcessTable_readCGroupFile(lp, procFd); -- cgit v1.2.3