Skip to content

Commit

Permalink
src: make InitializeOncePerProcess more flexible
Browse files Browse the repository at this point in the history
PR-URL: #38888
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
codebytere authored and targos committed Jun 11, 2021
1 parent 6d5dc63 commit 06afb8d
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 51 deletions.
122 changes: 71 additions & 51 deletions src/node.cc
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
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

0 comments on commit 06afb8d

Please sign in to comment.