diff options
author | Christian Göttsche <cgzones@googlemail.com> | 2023-05-05 20:23:15 +0200 |
---|---|---|
committer | cgzones <cgzones@googlemail.com> | 2024-04-06 19:42:28 +0200 |
commit | b4d5b5cea98f557a856c89500dc169f511a2b817 (patch) | |
tree | aa57a74027c0e3b9b91dc7d5ecd14bcab04d315b | |
parent | eb27a94ba411793aa1a25c331b3e1bb328739583 (diff) |
Linux: gather permitted capabilities via capget(2)
#1211 has shown reading /proc/<pid>/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.
-rw-r--r-- | Process.c | 2 | ||||
-rw-r--r-- | Process.h | 9 | ||||
-rw-r--r-- | linux/LinuxProcessTable.c | 23 |
3 files changed, 24 insertions, 10 deletions
@@ -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]; @@ -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 <stdio.h> #include <stdlib.h> #include <string.h> +#include <syscall.h> #include <unistd.h> +#include <linux/capability.h> // raw syscall, no libcap // IWYU pragma: keep // IWYU pragma: no_include <sys/capability.h> #include <sys/stat.h> #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); |