summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSam Roberts <vieuxtech@gmail.com>2017-02-20 06:18:43 -0800
committerSam Roberts <vieuxtech@gmail.com>2017-04-25 09:59:54 -0700
commitf2282bb812860284035d2a2ed8ac7074bf84cb50 (patch)
treed3ef613cb3e1e1fb8e1ceb852769cbdc51e64fca /src
parente522bcd774c6a43d8facc1905b59e53a86f7ae0a (diff)
downloadandroid-node-v8-f2282bb812860284035d2a2ed8ac7074bf84cb50.tar.gz
android-node-v8-f2282bb812860284035d2a2ed8ac7074bf84cb50.tar.bz2
android-node-v8-f2282bb812860284035d2a2ed8ac7074bf84cb50.zip
src: allow CLI args in env with NODE_OPTIONS
Not all CLI options are supported, those that are problematic from a security or implementation point of view are disallowed, as are ones that are inappropriate (for example, -e, -p, --i), or that only make sense when changed with code changes (such as options that change the javascript syntax or add new APIs). PR-URL: https://github.com/nodejs/node/pull/12028 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com> Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Gibson Fahnestock <gibfahn@gmail.com> Reviewed-By: Bradley Farias <bradley.meck@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/node.cc170
1 files changed, 133 insertions, 37 deletions
diff --git a/src/node.cc b/src/node.cc
index 6c4d2ac655..bb17a4139a 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -3626,6 +3626,9 @@ static void PrintHelp() {
#endif
#endif
"NODE_NO_WARNINGS set to 1 to silence process warnings\n"
+#if !defined(NODE_WITHOUT_NODE_OPTIONS)
+ "NODE_OPTIONS set CLI options in the environment\n"
+#endif
#ifdef _WIN32
"NODE_PATH ';'-separated list of directories\n"
#else
@@ -3642,6 +3645,51 @@ static void PrintHelp() {
}
+static void CheckIfAllowedInEnv(const char* exe, bool is_env,
+ const char* arg) {
+ if (!is_env)
+ return;
+
+ // Find the arg prefix when its --some_arg=val
+ const char* eq = strchr(arg, '=');
+ size_t arglen = eq ? eq - arg : strlen(arg);
+
+ static const char* whitelist[] = {
+ // Node options
+ "-r", "--require",
+ "--no-deprecation",
+ "--no-warnings",
+ "--trace-warnings",
+ "--redirect-warnings",
+ "--trace-deprecation",
+ "--trace-sync-io",
+ "--trace-events-enabled",
+ "--track-heap-objects",
+ "--throw-deprecation",
+ "--zero-fill-buffers",
+ "--v8-pool-size",
+ "--use-openssl-ca",
+ "--use-bundled-ca",
+ "--enable-fips",
+ "--force-fips",
+ "--openssl-config",
+ "--icu-data-dir",
+
+ // V8 options
+ "--max_old_space_size",
+ };
+
+ for (unsigned i = 0; i < arraysize(whitelist); i++) {
+ const char* allowed = whitelist[i];
+ if (strlen(allowed) == arglen && strncmp(allowed, arg, arglen) == 0)
+ return;
+ }
+
+ fprintf(stderr, "%s: %s is not allowed in NODE_OPTIONS\n", exe, arg);
+ exit(9);
+}
+
+
// Parse command line arguments.
//
// argv is modified in place. exec_argv and v8_argv are out arguments that
@@ -3658,7 +3706,8 @@ static void ParseArgs(int* argc,
int* exec_argc,
const char*** exec_argv,
int* v8_argc,
- const char*** v8_argv) {
+ const char*** v8_argv,
+ bool is_env) {
const unsigned int nargs = static_cast<unsigned int>(*argc);
const char** new_exec_argv = new const char*[nargs];
const char** new_v8_argv = new const char*[nargs];
@@ -3687,6 +3736,8 @@ static void ParseArgs(int* argc,
const char* const arg = argv[index];
unsigned int args_consumed = 1;
+ CheckIfAllowedInEnv(argv[0], is_env, arg);
+
if (debug_options.ParseOption(arg)) {
// Done, consumed by DebugOptions::ParseOption().
} else if (strcmp(arg, "--version") == 0 || strcmp(arg, "-v") == 0) {
@@ -3839,6 +3890,13 @@ static void ParseArgs(int* argc,
// Copy remaining arguments.
const unsigned int args_left = nargs - index;
+
+ if (is_env && args_left) {
+ fprintf(stderr, "%s: %s is not supported in NODE_OPTIONS\n",
+ argv[0], argv[index]);
+ exit(9);
+ }
+
memcpy(new_argv + new_argc, argv + index, args_left * sizeof(*argv));
new_argc += args_left;
@@ -4161,6 +4219,54 @@ inline void PlatformInit() {
}
+void ProcessArgv(int* argc,
+ const char** argv,
+ int* exec_argc,
+ const char*** exec_argv,
+ bool is_env = false) {
+ // Parse a few arguments which are specific to Node.
+ int v8_argc;
+ const char** v8_argv;
+ ParseArgs(argc, argv, exec_argc, exec_argv, &v8_argc, &v8_argv, is_env);
+
+ // TODO(bnoordhuis) Intercept --prof arguments and start the CPU profiler
+ // manually? That would give us a little more control over its runtime
+ // behavior but it could also interfere with the user's intentions in ways
+ // we fail to anticipate. Dillema.
+ for (int i = 1; i < v8_argc; ++i) {
+ if (strncmp(v8_argv[i], "--prof", sizeof("--prof") - 1) == 0) {
+ v8_is_profiling = true;
+ break;
+ }
+ }
+
+#ifdef __POSIX__
+ // Block SIGPROF signals when sleeping in epoll_wait/kevent/etc. Avoids the
+ // performance penalty of frequent EINTR wakeups when the profiler is running.
+ // Only do this for v8.log profiling, as it breaks v8::CpuProfiler users.
+ if (v8_is_profiling) {
+ uv_loop_configure(uv_default_loop(), UV_LOOP_BLOCK_SIGNAL, SIGPROF);
+ }
+#endif
+
+ // The const_cast doesn't violate conceptual const-ness. V8 doesn't modify
+ // the argv array or the elements it points to.
+ if (v8_argc > 1)
+ V8::SetFlagsFromCommandLine(&v8_argc, const_cast<char**>(v8_argv), true);
+
+ // Anything that's still in v8_argv is not a V8 or a node option.
+ for (int i = 1; i < v8_argc; i++) {
+ fprintf(stderr, "%s: bad option: %s\n", argv[0], v8_argv[i]);
+ }
+ delete[] v8_argv;
+ v8_argv = nullptr;
+
+ if (v8_argc > 1) {
+ exit(9);
+ }
+}
+
+
void Init(int* argc,
const char** argv,
int* exec_argc,
@@ -4214,31 +4320,36 @@ void Init(int* argc,
SafeGetenv("OPENSSL_CONF", &openssl_config);
#endif
- // Parse a few arguments which are specific to Node.
- int v8_argc;
- const char** v8_argv;
- ParseArgs(argc, argv, exec_argc, exec_argv, &v8_argc, &v8_argv);
-
- // TODO(bnoordhuis) Intercept --prof arguments and start the CPU profiler
- // manually? That would give us a little more control over its runtime
- // behavior but it could also interfere with the user's intentions in ways
- // we fail to anticipate. Dillema.
- for (int i = 1; i < v8_argc; ++i) {
- if (strncmp(v8_argv[i], "--prof", sizeof("--prof") - 1) == 0) {
- v8_is_profiling = true;
- break;
+#if !defined(NODE_WITHOUT_NODE_OPTIONS)
+ std::string node_options;
+ if (SafeGetenv("NODE_OPTIONS", &node_options)) {
+ // Smallest tokens are 2-chars (a not space and a space), plus 2 extra
+ // pointers, for the prepended executable name, and appended NULL pointer.
+ size_t max_len = 2 + (node_options.length() + 1) / 2;
+ const char** argv_from_env = new const char*[max_len];
+ int argc_from_env = 0;
+ // [0] is expected to be the program name, fill it in from the real argv.
+ argv_from_env[argc_from_env++] = argv[0];
+
+ char* cstr = strdup(node_options.c_str());
+ char* initptr = cstr;
+ char* token;
+ while ((token = strtok(initptr, " "))) { // NOLINT(runtime/threadsafe_fn)
+ initptr = nullptr;
+ argv_from_env[argc_from_env++] = token;
}
- }
-
-#ifdef __POSIX__
- // Block SIGPROF signals when sleeping in epoll_wait/kevent/etc. Avoids the
- // performance penalty of frequent EINTR wakeups when the profiler is running.
- // Only do this for v8.log profiling, as it breaks v8::CpuProfiler users.
- if (v8_is_profiling) {
- uv_loop_configure(uv_default_loop(), UV_LOOP_BLOCK_SIGNAL, SIGPROF);
+ argv_from_env[argc_from_env] = nullptr;
+ int exec_argc_;
+ const char** exec_argv_ = nullptr;
+ ProcessArgv(&argc_from_env, argv_from_env, &exec_argc_, &exec_argv_, true);
+ delete[] exec_argv_;
+ delete[] argv_from_env;
+ free(cstr);
}
#endif
+ ProcessArgv(argc, argv, exec_argc, exec_argv);
+
#if defined(NODE_HAVE_I18N_SUPPORT)
// If the parameter isn't given, use the env variable.
if (icu_data_dir.empty())
@@ -4250,21 +4361,6 @@ void Init(int* argc,
"(check NODE_ICU_DATA or --icu-data-dir parameters)");
}
#endif
- // The const_cast doesn't violate conceptual const-ness. V8 doesn't modify
- // the argv array or the elements it points to.
- if (v8_argc > 1)
- V8::SetFlagsFromCommandLine(&v8_argc, const_cast<char**>(v8_argv), true);
-
- // Anything that's still in v8_argv is not a V8 or a node option.
- for (int i = 1; i < v8_argc; i++) {
- fprintf(stderr, "%s: bad option: %s\n", argv[0], v8_argv[i]);
- }
- delete[] v8_argv;
- v8_argv = nullptr;
-
- if (v8_argc > 1) {
- exit(9);
- }
// Unconditionally force typed arrays to allocate outside the v8 heap. This
// is to prevent memory pointers from being moved around that are returned by