diff options
author | Nathan Scott <nathans@redhat.com> | 2021-03-17 14:29:40 +1100 |
---|---|---|
committer | Nathan Scott <nathans@redhat.com> | 2021-03-22 17:16:40 +1100 |
commit | 0ada9f325f69ddb0f917f023fa701ce7669cd370 (patch) | |
tree | 893a7f51aa87f25c965d4582587f771d95ba4b97 /linux/Platform.c | |
parent | 57e0ce7b4ffce8cf41bd3003831198d0bb38ebf2 (diff) |
Move libcap use to (Linux) platform-specific code
The libcap code is Linux-specific so move it all below
the linux/ platform subdirectory. As this feature has
custom command-line long options I provide a mechanism
whereby each platform can add custom long options that
augment the main htop options. We'll make use this of
this with the pcp/ platform in due course to implement
the --host and --archive options there.
Related to https://github.com/htop-dev/htop/pull/536
Diffstat (limited to 'linux/Platform.c')
-rw-r--r-- | linux/Platform.c | 173 |
1 files changed, 158 insertions, 15 deletions
diff --git a/linux/Platform.c b/linux/Platform.c index b0eaf113..a6885254 100644 --- a/linux/Platform.c +++ b/linux/Platform.c @@ -12,6 +12,7 @@ in the source distribution for its full text. #include <assert.h> #include <ctype.h> #include <dirent.h> +#include <errno.h> #include <fcntl.h> #include <inttypes.h> #include <math.h> @@ -61,11 +62,23 @@ in the source distribution for its full text. #include "zfs/ZfsArcStats.h" #include "zfs/ZfsCompressedArcMeter.h" +#ifdef HAVE_LIBCAP +#include <sys/capability.h> +#endif + #ifdef HAVE_SENSORS_SENSORS_H #include "LibSensors.h" #endif +#ifdef HAVE_LIBCAP +enum CapMode { + CAP_MODE_NONE, + CAP_MODE_BASIC, + CAP_MODE_STRICT +}; +#endif + const ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_VIRT, M_RESIDENT, M_SHARE, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 }; const SignalItem Platform_signals[] = { @@ -112,22 +125,9 @@ static time_t Platform_Battery_cacheTime; static double Platform_Battery_cachePercent = NAN; static ACPresence Platform_Battery_cacheIsOnAC; -void Platform_init(void) { - if (access(PROCDIR, R_OK) != 0) { - fprintf(stderr, "Error: could not read procfs (compiled to look in %s).\n", PROCDIR); - exit(1); - } - -#ifdef HAVE_SENSORS_SENSORS_H - LibSensors_init(NULL); +#ifdef HAVE_LIBCAP +static enum CapMode Platform_capabilitiesMode = CAP_MODE_BASIC; #endif -} - -void Platform_done(void) { -#ifdef HAVE_SENSORS_SENSORS_H - LibSensors_cleanup(); -#endif -} static Htop_Reaction Platform_actionSetIOPriority(State* st) { const LinuxProcess* p = (const LinuxProcess*) Panel_getSelected((Panel*)st->mainPanel); @@ -845,3 +845,146 @@ void Platform_getBattery(double* percent, ACPresence* isOnAC) { Platform_Battery_cacheIsOnAC = *isOnAC; Platform_Battery_cacheTime = now; } + +bool Platform_getLongOption(int opt, int argc, char** argv) { +#ifndef HAVE_LIBCAP + (void) argc; + (void) argv; +#endif + + switch (opt) { +#ifdef HAVE_LIBCAP + case 128: { + const char* mode = optarg; + if (!mode && optind < argc && argv[optind] != NULL && + (argv[optind][0] != '\0' && argv[optind][0] != '-')) { + mode = argv[optind++]; + } + + if (!mode || String_eq(mode, "basic")) { + Platform_capabilitiesMode = CAP_MODE_BASIC; + } else if (String_eq(mode, "none")) { + Platform_capabilitiesMode = CAP_MODE_NONE; + } else if (String_eq(mode, "strict")) { + Platform_capabilitiesMode = CAP_MODE_STRICT; + } else { + fprintf(stderr, "Error: invalid capabilities mode \"%s\".\n", mode); + exit(1); + } + break; + } +#endif + + default: + break; + } + return false; +} + +#ifdef HAVE_LIBCAP +static int dropCapabilities(enum CapMode mode) { + + if (mode == CAP_MODE_NONE) + return 0; + + /* capabilities we keep to operate */ + const cap_value_t keepcapsStrict[] = { + CAP_DAC_READ_SEARCH, + CAP_SYS_PTRACE, + }; + const cap_value_t keepcapsBasic[] = { + CAP_DAC_READ_SEARCH, /* read non world-readable process files of other users, like /proc/[pid]/io */ + CAP_KILL, /* send signals to processes of other users */ + CAP_SYS_NICE, /* lower process nice value / change nice value for arbitrary processes */ + CAP_SYS_PTRACE, /* read /proc/[pid]/exe */ +#ifdef HAVE_DELAYACCT + CAP_NET_ADMIN, /* communicate over netlink socket for delay accounting */ +#endif + }; + const cap_value_t* const keepcaps = (mode == CAP_MODE_BASIC) ? keepcapsBasic : keepcapsStrict; + const size_t ncap = (mode == CAP_MODE_BASIC) ? ARRAYSIZE(keepcapsBasic) : ARRAYSIZE(keepcapsStrict); + + cap_t caps = cap_init(); + if (caps == NULL) { + fprintf(stderr, "Error: can not initialize capabilities: %s\n", strerror(errno)); + return -1; + } + + if (cap_clear(caps) < 0) { + fprintf(stderr, "Error: can not clear capabilities: %s\n", strerror(errno)); + cap_free(caps); + return -1; + } + + cap_t currCaps = cap_get_proc(); + if (currCaps == NULL) { + fprintf(stderr, "Error: can not get current process capabilities: %s\n", strerror(errno)); + cap_free(caps); + return -1; + } + + for (size_t i = 0; i < ncap; i++) { + if (!CAP_IS_SUPPORTED(keepcaps[i])) + continue; + + cap_flag_value_t current; + if (cap_get_flag(currCaps, keepcaps[i], CAP_PERMITTED, ¤t) < 0) { + fprintf(stderr, "Error: can not get current value of capability %d: %s\n", keepcaps[i], strerror(errno)); + cap_free(currCaps); + cap_free(caps); + return -1; + } + + if (current != CAP_SET) + continue; + + if (cap_set_flag(caps, CAP_PERMITTED, 1, &keepcaps[i], CAP_SET) < 0) { + fprintf(stderr, "Error: can not set permitted capability %d: %s\n", keepcaps[i], strerror(errno)); + cap_free(currCaps); + cap_free(caps); + return -1; + } + + if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &keepcaps[i], CAP_SET) < 0) { + fprintf(stderr, "Error: can not set effective capability %d: %s\n", keepcaps[i], strerror(errno)); + cap_free(currCaps); + cap_free(caps); + return -1; + } + } + + if (cap_set_proc(caps) < 0) { + fprintf(stderr, "Error: can not set process capabilities: %s\n", strerror(errno)); + cap_free(currCaps); + cap_free(caps); + return -1; + } + + cap_free(currCaps); + cap_free(caps); + + return 0; +} +#endif + +void Platform_init(void) { +#ifdef HAVE_LIBCAP + if (dropCapabilities(Platform_capabilitiesMode) < 0) + exit(1); +#endif + + if (access(PROCDIR, R_OK) != 0) { + fprintf(stderr, "Error: could not read procfs (compiled to look in %s).\n", PROCDIR); + exit(1); + } + +#ifdef HAVE_SENSORS_SENSORS_H + LibSensors_init(NULL); +#endif +} + +void Platform_done(void) { +#ifdef HAVE_SENSORS_SENSORS_H + LibSensors_cleanup(); +#endif +} |