aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartosz Sosnowski <bartosz@janeasystems.com>2020-09-24 18:25:18 +0200
committerBartosz Sosnowski <bartosz@janeasystems.com>2020-09-24 18:25:18 +0200
commitabd8cdfc4e7d0d7f563a9b0f91523fe8395d5e25 (patch)
tree450b5f701a14a1c425811c9dd7db1c31b948b87a
parente36ffb72bebae55091304da51837ca204367dc16 (diff)
downloadios-node-v8-abd8cdfc4e7d0d7f563a9b0f91523fe8395d5e25.tar.gz
ios-node-v8-abd8cdfc4e7d0d7f563a9b0f91523fe8395d5e25.tar.bz2
ios-node-v8-abd8cdfc4e7d0d7f563a9b0f91523fe8395d5e25.zip
win, child_process: sanitize env variables
On Windows environment variables are case-insensitive. When spawning child process certain apps can get confused if some of the variables are duplicated. This adds a step on Windows to normalizeSpawnArguments that removes such duplicates, keeping only the first (in lexicographic order) entry in the env key of options. This is partly already done for the PATH entry. Fixes: https://github.com/nodejs/node/issues/35129 PR-URL: https://github.com/nodejs/node/pull/35210 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Denys Otrishko <shishugi@gmail.com>
-rw-r--r--doc/api/child_process.md4
-rw-r--r--lib/child_process.js20
-rw-r--r--test/parallel/test-child-process-env.js11
3 files changed, 34 insertions, 1 deletions
diff --git a/doc/api/child_process.md b/doc/api/child_process.md
index 3a5f64d622..235a2a80e7 100644
--- a/doc/api/child_process.md
+++ b/doc/api/child_process.md
@@ -43,6 +43,10 @@ the first one case-insensitively matching `PATH` to perform command lookup.
This may lead to issues on Windows when passing objects to `env` option that
have multiple variants of `PATH` variable.
+On Windows Node.js will sanitize the `env` by removing case-insensitive
+duplicates. Only first (in lexicographic order) entry will be passed to the
+child process.
+
The [`child_process.spawn()`][] method spawns the child process asynchronously,
without blocking the Node.js event loop. The [`child_process.spawnSync()`][]
function provides equivalent functionality in a synchronous manner that blocks
diff --git a/lib/child_process.js b/lib/child_process.js
index 9e1c37af8f..24c5e809ad 100644
--- a/lib/child_process.js
+++ b/lib/child_process.js
@@ -29,6 +29,7 @@ const {
ObjectDefineProperty,
ObjectPrototypeHasOwnProperty,
Promise,
+ Set,
} = primordials;
const {
@@ -524,8 +525,27 @@ function normalizeSpawnArguments(file, args, options) {
env.NODE_V8_COVERAGE = process.env.NODE_V8_COVERAGE;
}
+ let envKeys = [];
// Prototype values are intentionally included.
for (const key in env) {
+ envKeys.push(key);
+ }
+
+ if (process.platform === 'win32') {
+ // On Windows env keys are case insensitive. Filter out duplicates,
+ // keeping only the first one (in lexicographic order)
+ const sawKey = new Set();
+ envKeys = envKeys.sort().filter((key) => {
+ const uppercaseKey = key.toUpperCase();
+ if (sawKey.has(uppercaseKey)) {
+ return false;
+ }
+ sawKey.add(uppercaseKey);
+ return true;
+ });
+ }
+
+ for (const key of envKeys) {
const value = env[key];
if (value !== undefined) {
envPairs.push(`${key}=${value}`);
diff --git a/test/parallel/test-child-process-env.js b/test/parallel/test-child-process-env.js
index 783e392c3e..f9815ff015 100644
--- a/test/parallel/test-child-process-env.js
+++ b/test/parallel/test-child-process-env.js
@@ -36,7 +36,9 @@ const env = {
'HELLO': 'WORLD',
'UNDEFINED': undefined,
'NULL': null,
- 'EMPTY': ''
+ 'EMPTY': '',
+ 'duplicate': 'lowercase',
+ 'DUPLICATE': 'uppercase',
};
Object.setPrototypeOf(env, {
'FOO': 'BAR'
@@ -65,4 +67,11 @@ child.stdout.on('end', mustCall(() => {
assert.ok(!response.includes('UNDEFINED=undefined'));
assert.ok(response.includes('NULL=null'));
assert.ok(response.includes(`EMPTY=${os.EOL}`));
+ if (isWindows) {
+ assert.ok(response.includes('DUPLICATE=uppercase'));
+ assert.ok(!response.includes('duplicate=lowercase'));
+ } else {
+ assert.ok(response.includes('DUPLICATE=uppercase'));
+ assert.ok(response.includes('duplicate=lowercase'));
+ }
}));