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

Lines changed: 498 additions & 474 deletions

‎lib/internal/bootstrap/node.js‎

Lines changed: 20 additions & 6 deletions
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+
constcredentials=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+
constwrapped=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‎

Lines changed: 1 addition & 1 deletion
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‎

Lines changed: 35 additions & 38 deletions
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-
functionsetupProcessMethods(_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+
functionsetupProcessMethods(_chdir,_umask){
3933
process.chdir=functionchdir(directory){
4034
validateString(directory,'directory');
4135
return_chdir(directory);
@@ -51,10 +45,17 @@ function setupProcessMethods(_chdir, _umask, _initgroups, _setegid,
5145
};
5246
}
5347

54-
functionsetupPosixMethods(_initgroups,_setegid,_seteuid,
55-
_setgid,_setuid,_setgroups){
56-
57-
process.initgroups=functioninitgroups(user,extraGroup){
48+
functionwrapPosixCredentialSetters(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+
functioninitgroups(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
}elseif(result===2){
6566
thrownewERR_UNKNOWN_CREDENTIAL('Group',extraGroup);
6667
}
67-
};
68-
69-
process.setegid=functionsetegid(id){
70-
returnexecId(id,'Group',_setegid);
71-
};
72-
73-
process.seteuid=functionseteuid(id){
74-
returnexecId(id,'User',_seteuid);
75-
};
76-
77-
process.setgid=functionsetgid(id){
78-
returnexecId(id,'Group',_setgid);
79-
};
80-
81-
process.setuid=functionsetuid(id){
82-
returnexecId(id,'User',_setuid);
83-
};
68+
}
8469

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

100-
functionexecId(id,type,method){
101-
validateId(id,'id');
102-
// Result is 0 on success, 1 if credential is unknown.
103-
constresult=method(id);
104-
if(result===1){
105-
thrownewERR_UNKNOWN_CREDENTIAL(type,id);
106-
}
85+
functionwrapIdSetter(type,method){
86+
returnfunction(id){
87+
validateId(id,'id');
88+
// Result is 0 on success, 1 if credential is unknown.
89+
constresult=method(id);
90+
if(result===1){
91+
thrownewERR_UNKNOWN_CREDENTIAL(type,id);
92+
}
93+
};
10794
}
10895

10996
functionvalidateId(id,name){
@@ -113,6 +100,15 @@ function setupPosixMethods(_initgroups, _setegid, _seteuid,
113100
thrownewERR_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‎

Lines changed: 1 addition & 1 deletion
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
constconstants=internalBinding('constants').os;
2626
const{ deprecate }=require('internal/util');
2727
constisWindows=process.platform==='win32';

‎node.gyp‎

Lines changed: 1 addition & 0 deletions
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‎

Lines changed: 0 additions & 11 deletions
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‎

Lines changed: 1 addition & 1 deletion
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‎

Lines changed: 13 additions & 46 deletions
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
namespacenode {
@@ -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-
boolSafeGetenv(constchar* 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 (constchar* value = getenv(key)) {
517-
*text = value;
518-
returntrue;
519-
}
520-
}
521-
522-
fail:
523-
text->clear();
524-
returnfalse;
525-
}
526-
527-
528500
void* ArrayBufferAllocator::Allocate(size_t size) {
529501
if (zero_fill_field_ || per_process_opts->zero_fill_all_buffers)
530502
returnUncheckedCalloc(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‎

Lines changed: 1 addition & 0 deletions
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)