Skip to content

Commit

Permalink
src: allow CAP_NET_BIND_SERVICE in SafeGetenv
Browse files Browse the repository at this point in the history
This commit updates SafeGetenv to check if the current process has the
effective capability cap_net_bind_service set, and if so allows
environment variables to be read.

The motivation for this change is a use-case where Node is run in a
container, and the is a requirement to be able to listen to ports
below 1024. This is done by setting the capability of
cap_net_bind_service. In addition there is a need to set the
environment variable `NODE_EXTRA_CA_CERTS`. But currently this
environment variable will not be read when the capability has been set
on the executable.

PR-URL: #37727
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Richard Lau <rlau@redhat.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Michael Dawson <midawson@redhat.com>
  • Loading branch information
danbev committed Sep 24, 2021
1 parent 8e84d56 commit 3f61940
Showing 1 changed file with 36 additions and 1 deletion.
37 changes: 36 additions & 1 deletion src/node_credentials.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
#if !defined(_MSC_VER)
#include <unistd.h> // setuid, getuid
#endif
#ifdef __linux__
#include <linux/capability.h>
#include <sys/syscall.h>
#endif // __linux__

namespace node {

Expand All @@ -33,11 +37,42 @@ bool linux_at_secure = false;

namespace credentials {

// Look up environment variable unless running as setuid root.
#if defined(__linux__)
// Returns true if the current process only has the passed-in capability.
bool HasOnly(int capability) {
DCHECK(cap_valid(capability));

struct __user_cap_data_struct cap_data[2];
struct __user_cap_header_struct cap_header_data = {
_LINUX_CAPABILITY_VERSION_3,
getpid()};


if (syscall(SYS_capget, &cap_header_data, &cap_data) != 0) {
return false;
}
if (capability < 32) {
return cap_data[0].permitted ==
static_cast<unsigned int>(CAP_TO_MASK(capability));
}
return cap_data[1].permitted ==
static_cast<unsigned int>(CAP_TO_MASK(capability));
}
#endif

// Look up the environment variable and allow the lookup if the current
// process only has the capability CAP_NET_BIND_SERVICE set. If the current
// process does not have any capabilities set and the process is running as
// setuid root then lookup will not be allowed.
bool SafeGetenv(const char* key, std::string* text, Environment* env) {
#if !defined(__CloudABI__) && !defined(_WIN32)
#if defined(__linux__)
if ((!HasOnly(CAP_NET_BIND_SERVICE) && per_process::linux_at_secure) ||
getuid() != geteuid() || getgid() != getegid())
#else
if (per_process::linux_at_secure || getuid() != geteuid() ||
getgid() != getegid())
#endif
goto fail;
#endif

Expand Down

0 comments on commit 3f61940

Please sign in to comment.