From 42a11663e4d40fa7945fa209362fe8d507c0b1ca Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Wed, 17 Mar 2021 13:48:51 +0100 Subject: [PATCH] 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. --- src/node_credentials.cc | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/node_credentials.cc b/src/node_credentials.cc index fa3dfa48a3ceb24..8be279258443071 100644 --- a/src/node_credentials.cc +++ b/src/node_credentials.cc @@ -10,6 +10,7 @@ #if !defined(_MSC_VER) #include // setuid, getuid +#include #endif namespace node { @@ -33,11 +34,32 @@ bool linux_at_secure = false; namespace credentials { -// Look up environment variable unless running as setuid root. +#if !defined(__CloudABI__) && !defined(_WIN32) +// Returns true if the current process has effective capabilities and the +// passed-in capability is in that set. +bool HasCapability(int capability) { + DCHECK(cap_valid(capability)); + struct __user_cap_header_struct cap_header_data = { + _LINUX_CAPABILITY_VERSION_3, getpid() + }; + struct __user_cap_data_struct cap_data; + + if (capget(&cap_header_data, &cap_data) == -1) { + return false; + } + + return cap_data.effective & CAP_TO_MASK(capability); +} +#endif + +// Look up the environment variable and allow the lookup if the current +// process 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 (per_process::linux_at_secure || getuid() != geteuid() || - getgid() != getegid()) + if (!HasCapability(CAP_NET_BIND_SERVICE) && per_process::linux_at_secure || + getuid() != geteuid() || getgid() != getegid()) goto fail; #endif