diff options
author | Daniel Bevenius <daniel.bevenius@gmail.com> | 2021-03-17 15:48:51 +0300 |
---|---|---|
committer | Daniel Bevenius <daniel.bevenius@gmail.com> | 2021-09-24 06:56:43 +0300 |
commit | 3f619407fe1e597657b598383d0b5003a064311b (patch) | |
tree | a49211a6c3e8ebbc63a6f712a1da30fcc7d12597 /src/node_credentials.cc | |
parent | 8e84d566eababe9585864678e729c735a19e0085 (diff) |
src: allow CAP_NET_BIND_SERVICE in SafeGetenv
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: https://github.com/nodejs/node/pull/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>
Diffstat (limited to 'src/node_credentials.cc')
-rw-r--r-- | src/node_credentials.cc | 37 |
1 files changed, 36 insertions, 1 deletions
diff --git a/src/node_credentials.cc b/src/node_credentials.cc index fa3dfa48a3c..de0ba3c8be2 100644 --- a/src/node_credentials.cc +++ b/src/node_credentials.cc @@ -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 { @@ -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 |