summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Göttsche <cgzones@googlemail.com>2020-09-02 14:39:25 +0200
committerBenBE <BenBE@geshi.org>2021-01-11 20:19:51 +0100
commitf4404effa45ce378a8a72f2fff9641c7d7a0cc6f (patch)
tree742f042db6c21e5c2203bceb4a88c5b50bf744a8
parentd72b0a682ecad0a8d5793022733447e855a61798 (diff)
Add option to drop Linux capabilities
Conflicts with setuid support, but that is commonly not enabled.
-rw-r--r--.github/workflows/ci.yml16
-rw-r--r--configure.ac8
-rw-r--r--htop.1.in8
-rw-r--r--htop.c114
4 files changed, 138 insertions, 8 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 5de7c19e..a1c95ee6 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -59,15 +59,15 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Install Dependencies
- run: sudo apt-get install libncursesw5-dev libhwloc-dev libnl-3-dev libnl-genl-3-dev libsensors4-dev
+ run: sudo apt-get install libncursesw5-dev libhwloc-dev libnl-3-dev libnl-genl-3-dev libsensors4-dev libcap-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
- run: ./configure --enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct --with-sensors
+ run: ./configure --enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct --with-sensors --with-capabilities
- name: Build
run: make -k
- name: Distcheck
- run: make distcheck DISTCHECK_CONFIGURE_FLAGS='--enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct --with-sensors'
+ run: make distcheck DISTCHECK_CONFIGURE_FLAGS='--enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct --with-sensors --with-capabilities'
build-ubuntu-latest-full-featured-clang:
runs-on: ubuntu-latest
@@ -81,15 +81,15 @@ jobs:
sudo add-apt-repository 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-11 main' -y
sudo apt-get update -q
- name: Install Dependencies
- run: sudo apt-get install clang-11 libncursesw5-dev libhwloc-dev libnl-3-dev libnl-genl-3-dev libsensors4-dev
+ run: sudo apt-get install clang-11 libncursesw5-dev libhwloc-dev libnl-3-dev libnl-genl-3-dev libsensors4-dev libcap-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
- run: ./configure --enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct --with-sensors
+ run: ./configure --enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct --with-sensors --with-capabilities
- name: Build
run: make -k
- name: Distcheck
- run: make distcheck DISTCHECK_CONFIGURE_FLAGS='--enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct --with-sensors'
+ run: make distcheck DISTCHECK_CONFIGURE_FLAGS='--enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct --with-sensors --with-capabilities'
build-ubuntu-latest-clang-analyzer:
runs-on: ubuntu-latest
@@ -103,11 +103,11 @@ jobs:
sudo add-apt-repository 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-11 main' -y
sudo apt-get update -q
- name: Install Dependencies
- run: sudo apt-get install clang-11 clang-tools-11 libncursesw5-dev libhwloc-dev libnl-3-dev libnl-genl-3-dev libsensors4-dev
+ run: sudo apt-get install clang-11 clang-tools-11 libncursesw5-dev libhwloc-dev libnl-3-dev libnl-genl-3-dev libsensors4-dev libcap-dev
- name: Bootstrap
run: ./autogen.sh
- name: Configure
- run: scan-build-11 -analyze-headers --status-bugs ./configure --enable-debug --enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct --with-sensors
+ run: scan-build-11 -analyze-headers --status-bugs ./configure --enable-debug --enable-werror --enable-openvz --enable-vserver --enable-ancient-vserver --enable-unicode --enable-hwloc --enable-setuid --enable-delayacct --with-sensors --with-capabilities
- name: Build
run: scan-build-11 -analyze-headers --status-bugs make -j"$(nproc)"
diff --git a/configure.ac b/configure.ac
index 227f6b14..1feeb0fc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -307,6 +307,13 @@ if test "x$enable_setuid" = xyes; then
AC_DEFINE(HAVE_SETUID_ENABLED, 1, [Define if setuid support should be enabled.])
fi
+AC_ARG_WITH(capabilities, [AS_HELP_STRING([--with-capabilities], [Enable option to drop Linux capabilities via libcap])],, with_capabilities="no")
+if test "x$with_capabilities" = xyes
+then
+ AC_CHECK_LIB([cap], [cap_init], [], [missing_libraries="$missing_libraries libcap"])
+ AC_CHECK_HEADERS([sys/capability.h], [:], [missing_headers="$missing_headers $ac_header"])
+fi
+
AC_ARG_ENABLE(delayacct, [AS_HELP_STRING([--enable-delayacct], [enable Linux delay accounting])],, enable_delayacct="no")
if test "x$enable_delayacct" = xyes; then
m4_ifdef([PKG_PROG_PKG_CONFIG], [
@@ -408,6 +415,7 @@ AC_MSG_RESULT([
(Linux) affinity: $enable_linux_affinity
(Linux) delay accounting: $enable_delayacct
(Linux) sensors: $with_sensors
+ (Linux) capabilities: $with_capabilities
unicode: $enable_unicode
hwloc: $enable_hwloc
setuid: $enable_setuid
diff --git a/htop.1.in b/htop.1.in
index cd984789..2ab5c329 100644
--- a/htop.1.in
+++ b/htop.1.in
@@ -63,6 +63,14 @@ requesting a sort order with -s.
.TP
\fB\-H \-\-highlight-changes=DELAY\fR
Highlight new and old processes
+.TP
+\fB \-\-drop-capabilities[=none|basic|strict]\fR
+Linux only; requires libcap support.
+.br
+Drop unneeded Linux capabilities.
+In strict mode features like killing, changing process priorities, and reading
+process delay accounting information will not work, due to less capabilities
+held.
.SH "INTERACTIVE COMMANDS"
The following commands are supported while in
.BR htop :
diff --git a/htop.c b/htop.c
index e59c0282..ff5dc875 100644
--- a/htop.c
+++ b/htop.c
@@ -8,6 +8,7 @@ in the source distribution for its full text.
#include "config.h" // IWYU pragma: keep
#include <assert.h>
+#include <errno.h>
#include <getopt.h>
#include <locale.h>
#include <stdbool.h>
@@ -34,6 +35,19 @@ in the source distribution for its full text.
#include "UsersTable.h"
#include "XUtils.h"
+#ifdef HAVE_LIBCAP
+#include <sys/capability.h>
+#endif
+
+
+#ifdef HAVE_LIBCAP
+enum CapMode {
+ CAP_MODE_NONE,
+ CAP_MODE_BASIC,
+ CAP_MODE_STRICT
+};
+#endif
+
static void printVersionFlag(void) {
fputs(PACKAGE " " VERSION "\n", stdout);
}
@@ -46,6 +60,12 @@ static void printHelpFlag(void) {
"-d --delay=DELAY Set the delay between updates, in tenths of seconds\n"
"-F --filter=FILTER Show only the commands matching the given filter\n"
"-h --help Print this help screen\n"
+#ifdef HAVE_LIBCAP
+ " --drop-capabilities[=none|basic|strict] Drop Linux capabilities when running as root\n"
+ " none - do not drop any capabilities\n"
+ " basic (default) - drop all capabilities not needed by htop\n"
+ " strict - drop all capabilities except those needed for core functionality\n"
+#endif
"-H --highlight-changes[=DELAY] Highlight new and old processes\n"
"-M --no-mouse Disable the mouse\n"
"-p --pid=PID[,PID,PID...] Show only the given PIDs\n"
@@ -75,6 +95,9 @@ typedef struct CommandLineSettings_ {
bool allowUnicode;
bool highlightChanges;
int highlightDelaySecs;
+#ifdef HAVE_LIBCAP
+ enum CapMode capabilitiesMode;
+#endif
} CommandLineSettings;
static CommandLineSettings parseArguments(int argc, char** argv) {
@@ -91,6 +114,9 @@ static CommandLineSettings parseArguments(int argc, char** argv) {
.allowUnicode = true,
.highlightChanges = false,
.highlightDelaySecs = -1,
+#ifdef HAVE_LIBCAP
+ .capabilitiesMode = (geteuid() == 0) ? CAP_MODE_BASIC : CAP_MODE_NONE,
+#endif
};
const struct option long_opts[] =
@@ -108,6 +134,9 @@ static CommandLineSettings parseArguments(int argc, char** argv) {
{"pid", required_argument, 0, 'p'},
{"filter", required_argument, 0, 'F'},
{"highlight-changes", optional_argument, 0, 'H'},
+#ifdef HAVE_LIBCAP
+ {"drop-capabilities", optional_argument, 0, 128},
+#endif
{0,0,0,0}
};
@@ -225,6 +254,27 @@ static CommandLineSettings parseArguments(int argc, char** argv) {
flags.highlightChanges = true;
break;
}
+#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")) {
+ flags.capabilitiesMode = CAP_MODE_BASIC;
+ } else if (String_eq(mode, "none")) {
+ flags.capabilitiesMode = CAP_MODE_NONE;
+ } else if (String_eq(mode, "strict")) {
+ flags.capabilitiesMode = CAP_MODE_STRICT;
+ } else {
+ fprintf(stderr, "Error: invalid capabilities mode \"%s\".\n", mode);
+ exit(1);
+ }
+ break;
+ }
+#endif
default:
exit(1);
}
@@ -254,6 +304,65 @@ static void setCommFilter(State* state, char** commFilter) {
*commFilter = NULL;
}
+#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 int 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;
+ }
+
+ if (cap_set_flag(caps, CAP_PERMITTED, ncap, keepcaps, CAP_SET) < 0) {
+ fprintf(stderr, "Error: can not set permitted capabilities: %s\n", strerror(errno));
+ cap_free(caps);
+ return -1;
+ }
+
+ if (cap_set_flag(caps, CAP_EFFECTIVE, ncap, keepcaps, CAP_SET) < 0) {
+ fprintf(stderr, "Error: can not set effective capabilities: %s\n", strerror(errno));
+ 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(caps);
+ return -1;
+ }
+
+ cap_free(caps);
+
+ return 0;
+}
+#endif
+
int main(int argc, char** argv) {
/* initialize locale */
@@ -265,6 +374,11 @@ int main(int argc, char** argv) {
CommandLineSettings flags = parseArguments(argc, argv);
+#ifdef HAVE_LIBCAP
+ if (dropCapabilities(flags.capabilitiesMode) < 0)
+ exit(1);
+#endif
+
Platform_init();
Process_setupColumnWidths();

© 2014-2024 Faster IT GmbH | imprint | privacy policy