Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

src: make InitializeOncePerProcess more flexible #38888

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
122 changes: 71 additions & 51 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ int Environment::InitializeInspector(

return 0;
}
#endif // HAVE_INSPECTOR && NODE_USE_V8_PLATFORM
#endif // HAVE_INSPECTOR

#define ATOMIC_WAIT_EVENTS(V) \
V(kStartWait, "started") \
Expand Down Expand Up @@ -957,12 +957,26 @@ int InitializeNodeWithArgs(std::vector<std::string>* argv,
}

InitializationResult InitializeOncePerProcess(int argc, char** argv) {
return InitializeOncePerProcess(argc, argv, kDefaultInitialization);
}

InitializationResult InitializeOncePerProcess(
int argc,
char** argv,
InitializationSettingsFlags flags) {
uint64_t init_flags = flags;
if (init_flags & kDefaultInitialization) {
init_flags = init_flags | kInitializeV8 | kInitOpenSSL | kRunPlatformInit;
}

// Initialized the enabled list for Debug() calls with system
// environment variables.
per_process::enabled_debug_list.Parse(nullptr);

atexit(ResetStdio);
PlatformInit();

if (init_flags & kRunPlatformInit)
PlatformInit();

CHECK_GT(argc, 0);

Expand Down Expand Up @@ -1015,65 +1029,71 @@ InitializationResult InitializeOncePerProcess(int argc, char** argv) {
return result;
}

if (init_flags & kInitOpenSSL) {
#if HAVE_OPENSSL
{
std::string extra_ca_certs;
if (credentials::SafeGetenv("NODE_EXTRA_CA_CERTS", &extra_ca_certs))
crypto::UseExtraCaCerts(extra_ca_certs);
}
// In the case of FIPS builds we should make sure
// the random source is properly initialized first.
#if OPENSSL_VERSION_MAJOR >= 3
// Call OPENSSL_init_crypto to initialize OPENSSL_INIT_LOAD_CONFIG to
// avoid the default behavior where errors raised during the parsing of the
// OpenSSL configuration file are not propagated and cannot be detected.
//
// If FIPS is configured the OpenSSL configuration file will have an .include
// pointing to the fipsmodule.cnf file generated by the openssl fipsinstall
// command. If the path to this file is incorrect no error will be reported.
//
// For Node.js this will mean that EntropySource will be called by V8 as part
// of its initialization process, and EntropySource will in turn call
// CheckEntropy. CheckEntropy will call RAND_status which will now always
// return 0, leading to an endless loop and the node process will appear to
// hang/freeze.
std::string env_openssl_conf;
credentials::SafeGetenv("OPENSSL_CONF", &env_openssl_conf);

bool has_cli_conf = !per_process::cli_options->openssl_config.empty();
if (has_cli_conf || !env_openssl_conf.empty()) {
OPENSSL_INIT_SETTINGS* settings = OPENSSL_INIT_new();
OPENSSL_INIT_set_config_file_flags(settings, CONF_MFLAGS_DEFAULT_SECTION);
if (has_cli_conf) {
const char* conf = per_process::cli_options->openssl_config.c_str();
OPENSSL_INIT_set_config_filename(settings, conf);
{
std::string extra_ca_certs;
if (credentials::SafeGetenv("NODE_EXTRA_CA_CERTS", &extra_ca_certs))
crypto::UseExtraCaCerts(extra_ca_certs);
}
OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, settings);
OPENSSL_INIT_free(settings);

if (ERR_peek_error() != 0) {
result.exit_code = ERR_GET_REASON(ERR_peek_error());
result.early_return = true;
fprintf(stderr, "OpenSSL configuration error:\n");
ERR_print_errors_fp(stderr);
return result;
// In the case of FIPS builds we should make sure
// the random source is properly initialized first.
#if OPENSSL_VERSION_MAJOR >= 3
// Call OPENSSL_init_crypto to initialize OPENSSL_INIT_LOAD_CONFIG to
// avoid the default behavior where errors raised during the parsing of the
// OpenSSL configuration file are not propagated and cannot be detected.
//
// If FIPS is configured the OpenSSL configuration file will have an
// .include pointing to the fipsmodule.cnf file generated by the openssl
// fipsinstall command. If the path to this file is incorrect no error
// will be reported.
//
// For Node.js this will mean that EntropySource will be called by V8 as
// part of its initialization process, and EntropySource will in turn call
// CheckEntropy. CheckEntropy will call RAND_status which will now always
// return 0, leading to an endless loop and the node process will appear to
// hang/freeze.
std::string env_openssl_conf;
credentials::SafeGetenv("OPENSSL_CONF", &env_openssl_conf);

bool has_cli_conf = !per_process::cli_options->openssl_config.empty();
if (has_cli_conf || !env_openssl_conf.empty()) {
OPENSSL_INIT_SETTINGS* settings = OPENSSL_INIT_new();
OPENSSL_INIT_set_config_file_flags(settings, CONF_MFLAGS_DEFAULT_SECTION);
if (has_cli_conf) {
const char* conf = per_process::cli_options->openssl_config.c_str();
OPENSSL_INIT_set_config_filename(settings, conf);
}
OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, settings);
OPENSSL_INIT_free(settings);

if (ERR_peek_error() != 0) {
result.exit_code = ERR_GET_REASON(ERR_peek_error());
result.early_return = true;
fprintf(stderr, "OpenSSL configuration error:\n");
ERR_print_errors_fp(stderr);
return result;
}
}
}
#else
if (FIPS_mode()) {
OPENSSL_init();
}
if (FIPS_mode()) {
OPENSSL_init();
}
#endif
// V8 on Windows doesn't have a good source of entropy. Seed it from
// OpenSSL's pool.
V8::SetEntropySource(crypto::EntropySource);
// V8 on Windows doesn't have a good source of entropy. Seed it from
// OpenSSL's pool.
V8::SetEntropySource(crypto::EntropySource);
#endif // HAVE_OPENSSL

}
per_process::v8_platform.Initialize(
static_cast<int>(per_process::cli_options->v8_thread_pool_size));
V8::Initialize();
if (init_flags & kInitializeV8) {
V8::Initialize();
}

performance::performance_v8_start = PERFORMANCE_NOW();
per_process::v8_initialized = true;

return result;
}

Expand Down
13 changes: 13 additions & 0 deletions src/node_internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,20 @@ struct InitializationResult {
std::vector<std::string> exec_args;
bool early_return = false;
};

enum InitializationSettingsFlags : uint64_t {
kDefaultInitialization = 1 << 0,
kInitializeV8 = 1 << 1,
kRunPlatformInit = 1 << 2,
kInitOpenSSL = 1 << 3
};

// TODO(codebytere): eventually document and expose to embedders.
InitializationResult InitializeOncePerProcess(int argc, char** argv);
InitializationResult InitializeOncePerProcess(
int argc,
char** argv,
InitializationSettingsFlags flags);
void TearDownOncePerProcess();
void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s);
void SetIsolateMiscHandlers(v8::Isolate* isolate, const IsolateSettings& s);
Expand Down