diff --git a/pdns/capabilities.cc b/pdns/capabilities.cc index 534d66554229..e073d2c77bd6 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 4d0b0ded3c26..d12c6cb4d1d0 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 f86586a6a026..55943875d9d4 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