Skip to content

Commit

Permalink
dnsdist: Keep retained capabilities even when switching user/group
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
rgacogne committed Jul 5, 2022
1 parent cc2371c commit ab083b9
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 4 deletions.
36 changes: 35 additions & 1 deletion pdns/capabilities.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,13 @@

#ifdef HAVE_LIBCAP
#include <sys/capability.h>
#include <sys/prctl.h>
#endif

#include "capabilities.hh"
#include "misc.hh"

void dropCapabilities(std::set<std::string> capabilitiesToKeep)
bool dropCapabilities(std::set<std::string> capabilitiesToKeep)
{
#ifdef HAVE_LIBCAP
cap_t caps = cap_get_proc();
Expand Down Expand Up @@ -66,10 +67,43 @@ void dropCapabilities(std::set<std::string> 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 */
}
10 changes: 9 additions & 1 deletion pdns/capabilities.hh
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,12 @@

#include <set>

void dropCapabilities(std::set<std::string> 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<std::string> capabilitiesToKeep = {});
/* drop capabilities on setuid()/setgid() */
bool dropCapabilitiesAfterSwitchingIDs();
/* retain capabilities on setuid()/setgid() */
bool keepCapabilitiesAfterSwitchingIDs();
16 changes: 14 additions & 2 deletions pdns/dnsdist.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand All @@ -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
Expand Down

0 comments on commit ab083b9

Please sign in to comment.