From 06afb8df653d3a27b4580af369179f2f62f11ebe Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Tue, 1 Jun 2021 14:47:03 +0200 Subject: [PATCH] src: make InitializeOncePerProcess more flexible PR-URL: https://github.com/nodejs/node/pull/38888 Reviewed-By: Joyee Cheung Reviewed-By: Anna Henningsen Reviewed-By: James M Snell --- src/node.cc | 122 +++++++++++++++++++++++++------------------ src/node_internals.h | 13 +++++ 2 files changed, 84 insertions(+), 51 deletions(-) diff --git a/src/node.cc b/src/node.cc index 6c601fb920a04c..a9afbd2682f785 100644 --- a/src/node.cc +++ b/src/node.cc @@ -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") \ @@ -957,12 +957,26 @@ int InitializeNodeWithArgs(std::vector* 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); @@ -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(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; } diff --git a/src/node_internals.h b/src/node_internals.h index b75092d662dc97..31076551e70c46 100644 --- a/src/node_internals.h +++ b/src/node_internals.h @@ -316,7 +316,20 @@ struct InitializationResult { std::vector 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);