From dabf344de60d568e304a7f4d10548813ee4ce588 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Sun, 5 Feb 2023 13:17:21 +0000 Subject: [PATCH] networkd: Drop all capabilities except a few we would like to keep Signed-off-by: Michael Tremer --- Makefile.am | 2 + configure.ac | 1 + src/networkd/main.c | 121 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+) diff --git a/Makefile.am b/Makefile.am index 2ebe6224..df615527 100644 --- a/Makefile.am +++ b/Makefile.am @@ -334,12 +334,14 @@ networkd_CPPFLAGS = \ networkd_CFLAGS = \ $(AM_CFLAGS) \ + $(CAP_CFLAGS) \ $(SYSTEMD_CFLAGS) networkd_LDFLAGS = \ $(AM_LDFLAGS) networkd_LDADD = \ + $(CAP_LIBS) \ $(SYSTEMD_LIBS) dist_dbuspolicy_DATA += \ diff --git a/configure.ac b/configure.ac index 16f0724f..e1baa64b 100644 --- a/configure.ac +++ b/configure.ac @@ -172,6 +172,7 @@ AM_CONDITIONAL(HAVE_UDEV, [test -n "$with_udevdir"]) # ------------------------------------------------------------------------------ +PKG_CHECK_MODULES([CAP], [libcap]) PKG_CHECK_MODULES([LIBNL], [libnl-3.0 libnl-genl-3.0]) PKG_CHECK_MODULES([SYSTEMD], [libsystemd]) diff --git a/src/networkd/main.c b/src/networkd/main.c index fbd6c3b9..9a0fd74d 100644 --- a/src/networkd/main.c +++ b/src/networkd/main.c @@ -19,8 +19,10 @@ #############################################################################*/ #include +#include #include #include +#include #include #include #include @@ -28,6 +30,120 @@ #include "daemon.h" #include "logging.h" +static int cap_acquire_setpcap(void) { + cap_flag_value_t value; + int r; + + // Fetch current capabilities + cap_t caps = cap_get_proc(); + + // Check if CAP_SETPCAP is already enabled + r = cap_get_flag(caps, CAP_SETPCAP, CAP_EFFECTIVE, &value); + if (r) { + ERROR("The kernel does not seem to know CAP_SETPCAP: %m\n"); + goto ERROR; + } + + // It CAP_SETPCAP isn't set, we will try to set it + if (value != CAP_SET) { + const cap_value_t cap = CAP_SETPCAP; + + r = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, CAP_SET); + if (r) { + ERROR("Could not set CAP_SETPCAP: %m\n"); + goto ERROR; + } + + // Store capabilities + r = cap_set_proc(caps); + if (r) { + ERROR("Could not acquire effective CAP_SETPCAP capability: %m\n"); + goto ERROR; + } + } + +ERROR: + if (caps) + cap_free(caps); + + return r; +} + +static cap_flag_value_t keep_cap(const cap_value_t cap, const cap_value_t* keep_caps) { + for (const cap_value_t* c = keep_caps; *c; c++) { + if (cap == *c) + return CAP_SET; + } + + return CAP_CLEAR; +} + +static int drop_capabilities(void) { + int r; + + const cap_value_t keep_caps[] = { + CAP_NET_ADMIN, + CAP_NET_BIND_SERVICE, + CAP_NET_BROADCAST, + CAP_NET_RAW, + 0, + }; + + // Acquire CAP_SETPCAP + r = cap_acquire_setpcap(); + if (r) + return r; + + // Fetch the current set of capabilities + cap_t caps = cap_get_proc(); + + // Drop all capabilities that we do not need + for (cap_value_t cap = 1; cap <= CAP_LAST_CAP; cap++) { + // Skip any capabilities we would like to skip + cap_flag_value_t flag = keep_cap(cap, keep_caps); + + // Drop the capability from the bounding set + if (flag == CAP_CLEAR) { + r = prctl(PR_CAPBSET_DROP, cap); + if (r) { + ERROR("Could not drop capability from the bounding set: %m\n"); + goto ERROR; + } + } + + r = cap_set_flag(caps, CAP_INHERITABLE, 1, &cap, CAP_CLEAR); + if (r) { + ERROR("Could not set capability %d: %m\n", (int)cap); + goto ERROR; + } + + r = cap_set_flag(caps, CAP_PERMITTED, 1, &cap, flag); + if (r) { + ERROR("Could not set capability %d: %m\n", (int)cap); + goto ERROR; + } + + r = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, flag); + if (r) { + ERROR("Could not set capability %d: %m\n", (int)cap); + goto ERROR; + } + } + + // Restore capabilities + r = cap_set_proc(caps); + if (r) { + ERROR("Could not restore capabilities: %m\n"); + goto ERROR; + } + +ERROR: + if (caps) + cap_free(caps); + + return r; +} + static int drop_privileges(const char* user) { struct passwd* passwd = NULL; int r; @@ -87,6 +203,11 @@ static int drop_privileges(const char* user) { return 1; } + // Drop capabilities + r = drop_capabilities(); + if (r) + return r; + return 0; } -- 2.39.2