From: Remi Gacogne Date: Tue, 5 Jul 2022 15:48:14 +0000 (+0200) Subject: dnsdist: Keep retained capabilities even when switching user/group X-Git-Tag: auth-4.8.0-alpha0~22^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fpull%2F11761%2Fhead;p=thirdparty%2Fpdns.git dnsdist: Keep retained capabilities even when switching user/group On Linux, we support retaining some capabilities if we are running as root (eeew) or as an unprivileged user with ambiant capabilities, but we did not yet support keeping these if we were started as root but then switched to a different user ID and/or group ID. This commit uses `PR_SET_KEEPCAPS`, when available, to do just that, to be able to retain the capabilities we need without running as a fully privileged users even when we cannot easily use ambiant capabilities. --- diff --git a/pdns/capabilities.cc b/pdns/capabilities.cc index 534d665542..e073d2c77b 100644 --- a/pdns/capabilities.cc +++ b/pdns/capabilities.cc @@ -27,12 +27,13 @@ #ifdef HAVE_LIBCAP #include +#include #endif #include "capabilities.hh" #include "misc.hh" -void dropCapabilities(std::set capabilitiesToKeep) +bool dropCapabilities(std::set capabilitiesToKeep) { #ifdef HAVE_LIBCAP cap_t caps = cap_get_proc(); @@ -66,10 +67,43 @@ void dropCapabilities(std::set capabilitiesToKeep) if (cap_set_proc(caps) != 0) { cap_free(caps); + if (errno == EPERM) { + return false; + } throw std::runtime_error("Unable to drop capabilities: " + stringerror()); } cap_free(caps); + return true; } +#endif /* HAVE_LIBCAP */ + return false; +} + +bool dropCapabilitiesAfterSwitchingIDs() +{ +#ifdef HAVE_LIBCAP +#ifdef PR_SET_KEEPCAPS + if (prctl(PR_SET_KEEPCAPS, 0, 0, 0, 0) == 0) { + return true; + } +#endif /* PR_SET_KEEPCAPS */ + return false; +#else + return false; +#endif /* HAVE_LIBCAP */ +} + +bool keepCapabilitiesAfterSwitchingIDs() +{ +#ifdef HAVE_LIBCAP +#ifdef PR_SET_KEEPCAPS + if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == 0) { + return true; + } +#endif /* PR_SET_KEEPCAPS */ + return false; +#else + return false; #endif /* HAVE_LIBCAP */ } diff --git a/pdns/capabilities.hh b/pdns/capabilities.hh index 4d0b0ded3c..d12c6cb4d1 100644 --- a/pdns/capabilities.hh +++ b/pdns/capabilities.hh @@ -23,4 +23,12 @@ #include -void dropCapabilities(std::set capabilitiesToKeep = {}); +/* return true on success, false if support is not available or we don't + have enough capabilities to drop our capabilities (I know), + and throw on more unexpected errors. +*/ +bool dropCapabilities(std::set capabilitiesToKeep = {}); +/* drop capabilities on setuid()/setgid() */ +bool dropCapabilitiesAfterSwitchingIDs(); +/* retain capabilities on setuid()/setgid() */ +bool keepCapabilitiesAfterSwitchingIDs(); diff --git a/pdns/dnsdist.cc b/pdns/dnsdist.cc index f86586a6a0..55943875d9 100644 --- a/pdns/dnsdist.cc +++ b/pdns/dnsdist.cc @@ -2617,11 +2617,19 @@ int main(int argc, char** argv) uid_t newgid=getegid(); gid_t newuid=geteuid(); - if(!g_cmdLine.gid.empty()) + if (!g_cmdLine.gid.empty()) { newgid = strToGID(g_cmdLine.gid.c_str()); + } - if(!g_cmdLine.uid.empty()) + if (!g_cmdLine.uid.empty()) { newuid = strToUID(g_cmdLine.uid.c_str()); + } + + bool retainedCapabilities = true; + if (!g_capabilitiesToRetain.empty() && + (getegid() != newgid || geteuid() != newuid)) { + retainedCapabilities = keepCapabilitiesAfterSwitchingIDs(); + } if (getegid() != newgid) { if (running_in_service_mgr()) { @@ -2639,6 +2647,10 @@ int main(int argc, char** argv) dropUserPrivs(newuid); } + if (retainedCapabilities) { + dropCapabilitiesAfterSwitchingIDs(); + } + try { /* we might still have capabilities remaining, for example if we have been started as root