Skip to content

Commit e93dd4d

Browse files
joyeecheungaddaleax
authored andcommitted
process: move POSIX credential accessors into node_credentials.cc
Expose the POSIX credential accessors through `internalBinding('credentials')` instead of setting them on the process or bootstrapper object from C++ directly. Also moves `SafeGetEnv` from `internalBinding('util')` to `internalBinding('credentials')` since it's closely related to the credentials. In the JS land, instead of wrapping the bindings then writing to the process object directly in main_thread_only.js, return the wrapped functions back to bootstrap/node.js where they get written to the process object conditionally for clarity. Refs: #24961 PR-URL: #25066 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 37ba201 commit e93dd4d

17 files changed

+498
-474
lines changed

lib/internal/bootstrap/node.js

+20-6
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ const {
2323
_setupPromises, _chdir, _cpuUsage,
2424
_hrtime, _hrtimeBigInt,
2525
_memoryUsage, _rawDebug,
26-
_umask, _initgroups, _setegid, _seteuid,
27-
_setgid, _setuid, _setgroups,
26+
_umask,
2827
_shouldAbortOnUncaughtToggle
2928
} = bootstrappers;
3029
const { internalBinding, NativeModule } = loaderExports;
@@ -73,13 +72,28 @@ function startup() {
7372
NativeModule.require('internal/process/warning').setup();
7473
NativeModule.require('internal/process/next_tick').setup(_setupNextTick,
7574
_setupPromises);
75+
const credentials = internalBinding('credentials');
76+
if (credentials.implementsPosixCredentials) {
77+
process.getuid = credentials.getuid;
78+
process.geteuid = credentials.geteuid;
79+
process.getgid = credentials.getgid;
80+
process.getegid = credentials.getegid;
81+
process.getgroups = credentials.getgroups;
82+
83+
if (isMainThread) {
84+
const wrapped = mainThreadSetup.wrapPosixCredentialSetters(credentials);
85+
process.initgroups = wrapped.initgroups;
86+
process.setgroups = wrapped.setgroups;
87+
process.setegid = wrapped.setegid;
88+
process.seteuid = wrapped.seteuid;
89+
process.setgid = wrapped.setgid;
90+
process.setuid = wrapped.setuid;
91+
}
92+
}
7693

7794
if (isMainThread) {
7895
mainThreadSetup.setupStdio();
79-
mainThreadSetup.setupProcessMethods(
80-
_chdir, _umask, _initgroups, _setegid, _seteuid,
81-
_setgid, _setuid, _setgroups
82-
);
96+
mainThreadSetup.setupProcessMethods(_chdir, _umask);
8397
} else {
8498
workerThreadSetup.setupStdio();
8599
}

lib/internal/modules/cjs/loader.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ const {
3434
internalModuleReadJSON,
3535
internalModuleStat
3636
} = internalBinding('fs');
37-
const { safeGetenv } = internalBinding('util');
37+
const { safeGetenv } = internalBinding('credentials');
3838
const {
3939
makeRequireFunction,
4040
requireDepth,

lib/internal/process/main_thread_only.js

+35-38
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,7 @@ function setupStdio() {
2929

3030
// Non-POSIX platforms like Windows don't have certain methods.
3131
// Workers also lack these methods since they change process-global state.
32-
function setupProcessMethods(_chdir, _umask, _initgroups, _setegid,
33-
_seteuid, _setgid, _setuid, _setgroups) {
34-
if (_setgid !== undefined) {
35-
setupPosixMethods(_initgroups, _setegid, _seteuid,
36-
_setgid, _setuid, _setgroups);
37-
}
38-
32+
function setupProcessMethods(_chdir, _umask) {
3933
process.chdir = function chdir(directory) {
4034
validateString(directory, 'directory');
4135
return _chdir(directory);
@@ -51,10 +45,17 @@ function setupProcessMethods(_chdir, _umask, _initgroups, _setegid,
5145
};
5246
}
5347

54-
function setupPosixMethods(_initgroups, _setegid, _seteuid,
55-
_setgid, _setuid, _setgroups) {
56-
57-
process.initgroups = function initgroups(user, extraGroup) {
48+
function wrapPosixCredentialSetters(credentials) {
49+
const {
50+
initgroups: _initgroups,
51+
setgroups: _setgroups,
52+
setegid: _setegid,
53+
seteuid: _seteuid,
54+
setgid: _setgid,
55+
setuid: _setuid
56+
} = credentials;
57+
58+
function initgroups(user, extraGroup) {
5859
validateId(user, 'user');
5960
validateId(extraGroup, 'extraGroup');
6061
// Result is 0 on success, 1 if user is unknown, 2 if group is unknown.
@@ -64,25 +65,9 @@ function setupPosixMethods(_initgroups, _setegid, _seteuid,
6465
} else if (result === 2) {
6566
throw new ERR_UNKNOWN_CREDENTIAL('Group', extraGroup);
6667
}
67-
};
68-
69-
process.setegid = function setegid(id) {
70-
return execId(id, 'Group', _setegid);
71-
};
72-
73-
process.seteuid = function seteuid(id) {
74-
return execId(id, 'User', _seteuid);
75-
};
76-
77-
process.setgid = function setgid(id) {
78-
return execId(id, 'Group', _setgid);
79-
};
80-
81-
process.setuid = function setuid(id) {
82-
return execId(id, 'User', _setuid);
83-
};
68+
}
8469

85-
process.setgroups = function setgroups(groups) {
70+
function setgroups(groups) {
8671
if (!Array.isArray(groups)) {
8772
throw new ERR_INVALID_ARG_TYPE('groups', 'Array', groups);
8873
}
@@ -95,15 +80,17 @@ function setupPosixMethods(_initgroups, _setegid, _seteuid,
9580
if (result > 0) {
9681
throw new ERR_UNKNOWN_CREDENTIAL('Group', groups[result - 1]);
9782
}
98-
};
83+
}
9984

100-
function execId(id, type, method) {
101-
validateId(id, 'id');
102-
// Result is 0 on success, 1 if credential is unknown.
103-
const result = method(id);
104-
if (result === 1) {
105-
throw new ERR_UNKNOWN_CREDENTIAL(type, id);
106-
}
85+
function wrapIdSetter(type, method) {
86+
return function(id) {
87+
validateId(id, 'id');
88+
// Result is 0 on success, 1 if credential is unknown.
89+
const result = method(id);
90+
if (result === 1) {
91+
throw new ERR_UNKNOWN_CREDENTIAL(type, id);
92+
}
93+
};
10794
}
10895

10996
function validateId(id, name) {
@@ -113,6 +100,15 @@ function setupPosixMethods(_initgroups, _setegid, _seteuid,
113100
throw new ERR_INVALID_ARG_TYPE(name, ['number', 'string'], id);
114101
}
115102
}
103+
104+
return {
105+
initgroups,
106+
setgroups,
107+
setegid: wrapIdSetter('Group', _setegid),
108+
seteuid: wrapIdSetter('User', _seteuid),
109+
setgid: wrapIdSetter('Group', _setgid),
110+
setuid: wrapIdSetter('User', _setuid)
111+
};
116112
}
117113

118114
// Worker threads don't receive signals.
@@ -181,5 +177,6 @@ module.exports = {
181177
setupStdio,
182178
setupProcessMethods,
183179
setupSignalHandlers,
184-
setupChildProcessIpcChannel
180+
setupChildProcessIpcChannel,
181+
wrapPosixCredentialSetters
185182
};

lib/os.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
'use strict';
2323

24-
const { safeGetenv } = internalBinding('util');
24+
const { safeGetenv } = internalBinding('credentials');
2525
const constants = internalBinding('constants').os;
2626
const { deprecate } = require('internal/util');
2727
const isWindows = process.platform === 'win32';

node.gyp

+1
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,7 @@
352352
'src/node_config.cc',
353353
'src/node_constants.cc',
354354
'src/node_contextify.cc',
355+
'src/node_credentials.cc',
355356
'src/node_domain.cc',
356357
'src/node_encoding.cc',
357358
'src/node_env_var.cc',

src/bootstrapper.cc

-11
Original file line numberDiff line numberDiff line change
@@ -147,17 +147,6 @@ void SetupBootstrapObject(Environment* env,
147147
BOOTSTRAP_METHOD(_rawDebug, RawDebug);
148148
BOOTSTRAP_METHOD(_umask, Umask);
149149

150-
#if defined(__POSIX__) && !defined(__ANDROID__) && !defined(__CloudABI__)
151-
if (env->is_main_thread()) {
152-
BOOTSTRAP_METHOD(_initgroups, InitGroups);
153-
BOOTSTRAP_METHOD(_setegid, SetEGid);
154-
BOOTSTRAP_METHOD(_seteuid, SetEUid);
155-
BOOTSTRAP_METHOD(_setgid, SetGid);
156-
BOOTSTRAP_METHOD(_setuid, SetUid);
157-
BOOTSTRAP_METHOD(_setgroups, SetGroups);
158-
}
159-
#endif // __POSIX__ && !defined(__ANDROID__) && !defined(__CloudABI__)
160-
161150
Local<String> should_abort_on_uncaught_toggle =
162151
FIXED_ONE_BYTE_STRING(env->isolate(), "_shouldAbortOnUncaughtToggle");
163152
CHECK(bootstrapper->Set(env->context(),

src/env.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ Environment::Environment(IsolateData* isolate_data,
227227
should_abort_on_uncaught_toggle_[0] = 1;
228228

229229
std::string debug_cats;
230-
SafeGetenv("NODE_DEBUG_NATIVE", &debug_cats);
230+
credentials::SafeGetenv("NODE_DEBUG_NATIVE", &debug_cats);
231231
set_debug_categories(debug_cats, true);
232232

233233
isolate()->GetHeapProfiler()->AddBuildEmbedderGraphCallback(

src/node.cc

+13-46
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,7 @@ typedef int mode_t;
100100
#else
101101
#include <pthread.h>
102102
#include <sys/resource.h> // getrlimit, setrlimit
103-
#include <unistd.h> // setuid, getuid
104-
#endif
105-
106-
#if defined(__POSIX__) && !defined(__ANDROID__) && !defined(__CloudABI__)
107-
#include <pwd.h> // getpwnam()
108-
#include <grp.h> // getgrnam()
103+
#include <unistd.h> // STDIN_FILENO, STDERR_FILENO
109104
#endif
110105

111106
namespace node {
@@ -153,8 +148,6 @@ unsigned int reverted = 0;
153148

154149
bool v8_initialized = false;
155150

156-
bool linux_at_secure = false;
157-
158151
// process-relative uptime base, initialized at start-up
159152
double prog_start_time;
160153

@@ -504,27 +497,6 @@ const char* signo_string(int signo) {
504497
}
505498
}
506499

507-
// Look up environment variable unless running as setuid root.
508-
bool SafeGetenv(const char* key, std::string* text) {
509-
#if !defined(__CloudABI__) && !defined(_WIN32)
510-
if (linux_at_secure || getuid() != geteuid() || getgid() != getegid())
511-
goto fail;
512-
#endif
513-
514-
{
515-
Mutex::ScopedLock lock(environ_mutex);
516-
if (const char* value = getenv(key)) {
517-
*text = value;
518-
return true;
519-
}
520-
}
521-
522-
fail:
523-
text->clear();
524-
return false;
525-
}
526-
527-
528500
void* ArrayBufferAllocator::Allocate(size_t size) {
529501
if (zero_fill_field_ || per_process_opts->zero_fill_all_buffers)
530502
return UncheckedCalloc(size);
@@ -1165,14 +1137,6 @@ void SetupProcessObject(Environment* env,
11651137
env->SetMethod(process, "dlopen", binding::DLOpen);
11661138
env->SetMethod(process, "reallyExit", Exit);
11671139
env->SetMethodNoSideEffect(process, "uptime", Uptime);
1168-
1169-
#if defined(__POSIX__) && !defined(__ANDROID__) && !defined(__CloudABI__)
1170-
env->SetMethodNoSideEffect(process, "getuid", GetUid);
1171-
env->SetMethodNoSideEffect(process, "geteuid", GetEUid);
1172-
env->SetMethodNoSideEffect(process, "getgid", GetGid);
1173-
env->SetMethodNoSideEffect(process, "getegid", GetEGid);
1174-
env->SetMethodNoSideEffect(process, "getgroups", GetGroups);
1175-
#endif // __POSIX__ && !defined(__ANDROID__) && !defined(__CloudABI__)
11761140
}
11771141

11781142

@@ -1633,37 +1597,40 @@ void Init(std::vector<std::string>* argv,
16331597
{
16341598
std::string text;
16351599
default_env_options->pending_deprecation =
1636-
SafeGetenv("NODE_PENDING_DEPRECATION", &text) && text[0] == '1';
1600+
credentials::SafeGetenv("NODE_PENDING_DEPRECATION", &text) &&
1601+
text[0] == '1';
16371602
}
16381603

16391604
// Allow for environment set preserving symlinks.
16401605
{
16411606
std::string text;
16421607
default_env_options->preserve_symlinks =
1643-
SafeGetenv("NODE_PRESERVE_SYMLINKS", &text) && text[0] == '1';
1608+
credentials::SafeGetenv("NODE_PRESERVE_SYMLINKS", &text) &&
1609+
text[0] == '1';
16441610
}
16451611

16461612
{
16471613
std::string text;
16481614
default_env_options->preserve_symlinks_main =
1649-
SafeGetenv("NODE_PRESERVE_SYMLINKS_MAIN", &text) && text[0] == '1';
1615+
credentials::SafeGetenv("NODE_PRESERVE_SYMLINKS_MAIN", &text) &&
1616+
text[0] == '1';
16501617
}
16511618

16521619
if (default_env_options->redirect_warnings.empty()) {
1653-
SafeGetenv("NODE_REDIRECT_WARNINGS",
1654-
&default_env_options->redirect_warnings);
1620+
credentials::SafeGetenv("NODE_REDIRECT_WARNINGS",
1621+
&default_env_options->redirect_warnings);
16551622
}
16561623

16571624
#if HAVE_OPENSSL
16581625
std::string* openssl_config = &per_process_opts->openssl_config;
16591626
if (openssl_config->empty()) {
1660-
SafeGetenv("OPENSSL_CONF", openssl_config);
1627+
credentials::SafeGetenv("OPENSSL_CONF", openssl_config);
16611628
}
16621629
#endif
16631630

16641631
#if !defined(NODE_WITHOUT_NODE_OPTIONS)
16651632
std::string node_options;
1666-
if (SafeGetenv("NODE_OPTIONS", &node_options)) {
1633+
if (credentials::SafeGetenv("NODE_OPTIONS", &node_options)) {
16671634
std::vector<std::string> env_argv;
16681635
// [0] is expected to be the program name, fill it in from the real argv.
16691636
env_argv.push_back(argv->at(0));
@@ -1695,7 +1662,7 @@ void Init(std::vector<std::string>* argv,
16951662
#if defined(NODE_HAVE_I18N_SUPPORT)
16961663
// If the parameter isn't given, use the env variable.
16971664
if (per_process_opts->icu_data_dir.empty())
1698-
SafeGetenv("NODE_ICU_DATA", &per_process_opts->icu_data_dir);
1665+
credentials::SafeGetenv("NODE_ICU_DATA", &per_process_opts->icu_data_dir);
16991666
// Initialize ICU.
17001667
// If icu_data_dir is empty here, it will load the 'minimal' data.
17011668
if (!i18n::InitializeICUDirectory(per_process_opts->icu_data_dir)) {
@@ -2103,7 +2070,7 @@ int Start(int argc, char** argv) {
21032070
#if HAVE_OPENSSL
21042071
{
21052072
std::string extra_ca_certs;
2106-
if (SafeGetenv("NODE_EXTRA_CA_CERTS", &extra_ca_certs))
2073+
if (credentials::SafeGetenv("NODE_EXTRA_CA_CERTS", &extra_ca_certs))
21072074
crypto::UseExtraCaCerts(extra_ca_certs);
21082075
}
21092076
#ifdef NODE_FIPS_MODE

src/node_binding.cc

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
V(cares_wrap) \
2727
V(config) \
2828
V(contextify) \
29+
V(credentials) \
2930
V(domain) \
3031
V(fs) \
3132
V(fs_event_wrap) \

0 commit comments

Comments
 (0)