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

child_process.spawn not checking null byte in args #44768

Closed
t-tera opened this issue Sep 24, 2022 · 6 comments · Fixed by #44782
Closed

child_process.spawn not checking null byte in args #44768

t-tera opened this issue Sep 24, 2022 · 6 comments · Fixed by #44782
Labels
child_process Issues and PRs related to the child_process subsystem.

Comments

@t-tera
Copy link

t-tera commented Sep 24, 2022

Version

v18.9.1

Platform

Linux tsc-ubuntu2204 5.15.0-48-generic #54-Ubuntu SMP Fri Aug 26 13:26:29 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

Subsystem

child_process

What steps will reproduce the bug?

//// spawner.js
const {spawn} = require('child_process');

const myArgs = ['dump.js','AAA','BBB\0XXX', 'CCC'];
console.log('spawner.js:', myArgs);

const childProcess = spawn('node', myArgs);

childProcess.stdout.on('data', (chunk) => {
  console.log(chunk.toString());
});
//// dump.js
console.log('dump.js:', process.argv);
$ node spawner.js
spawner.js: [ 'dump.js', 'AAA', 'BBB\x00XXX', 'CCC' ]
dump.js: [ '/usr/local/bin/node', '/tmp/dump.js', 'AAA', 'BBB', 'CCC' ]

How often does it reproduce? Is there a required condition?

No particular condition required.

What is the expected behavior?

Node.js should raise error when invalid args (containing null byte) are given.

What do you see instead?

No error raised. Null byte and subsequent bytes are silently truncated.

Additional information

Other languages below have null byte checking and raise error in the same situation.

Java:   java.io.IOException: invalid null character in command
PHP:    Uncaught ValueError: Command array element 4 contains a null byte
Python: ValueError: embedded null byte
Ruby:   ArgumentError (string contains null byte)

IMO raising error is safer to avoid null byte injection.

@VoltrexKeyva VoltrexKeyva added the child_process Issues and PRs related to the child_process subsystem. label Sep 24, 2022
@bnoordhuis
Copy link
Member

I agree this ought to be fixed, for consistency with node's fs module (which rejects paths with nul bytes) if nothing else. Pull request welcome.

RaisinTen added a commit to RaisinTen/node that referenced this issue Sep 25, 2022
This change adds validation to reject an edge case where the
child_process.spawn() argument strings might contain null bytes
somewhere in between. Such strings were being silently truncated
before, so throwing an error should prevent misuses of this API.

Fixes: nodejs#44768
Signed-off-by: Darshan Sen <raisinten@gmail.com>
@RaisinTen
Copy link
Contributor

Sent a PR which adds the required validation: #44782

RaisinTen added a commit to RaisinTen/node that referenced this issue Sep 25, 2022
This change adds validation to reject an edge case where the
child_process.spawn() argument strings might contain null bytes
somewhere in between. Such strings were being silently truncated
before, so throwing an error should prevent misuses of this API.

Fixes: nodejs#44768
Signed-off-by: Darshan Sen <raisinten@gmail.com>
RaisinTen added a commit to RaisinTen/node that referenced this issue Oct 3, 2022
This change adds validation to reject an edge case where the
child_process API argument strings might contain null bytes
somewhere in between. Such strings were being silently truncated
before, so throwing an error should prevent misuses of this API.

Fixes: nodejs#44768
Signed-off-by: Darshan Sen <raisinten@gmail.com>
nodejs-github-bot pushed a commit that referenced this issue Oct 14, 2022
This change adds validation to reject an edge case where the
child_process API argument strings might contain null bytes
somewhere in between. Such strings were being silently truncated
before, so throwing an error should prevent misuses of this API.

Fixes: #44768
Signed-off-by: Darshan Sen <raisinten@gmail.com>
PR-URL: #44782
Reviewed-By: James M Snell <jasnell@gmail.com>
RafaelGSS pushed a commit that referenced this issue Nov 1, 2022
This change adds validation to reject an edge case where the
child_process API argument strings might contain null bytes
somewhere in between. Such strings were being silently truncated
before, so throwing an error should prevent misuses of this API.

Fixes: #44768
Signed-off-by: Darshan Sen <raisinten@gmail.com>
PR-URL: #44782
Reviewed-By: James M Snell <jasnell@gmail.com>
RafaelGSS pushed a commit that referenced this issue Nov 10, 2022
This change adds validation to reject an edge case where the
child_process API argument strings might contain null bytes
somewhere in between. Such strings were being silently truncated
before, so throwing an error should prevent misuses of this API.

Fixes: #44768
Signed-off-by: Darshan Sen <raisinten@gmail.com>
PR-URL: #44782
Reviewed-By: James M Snell <jasnell@gmail.com>
danielleadams pushed a commit that referenced this issue Dec 30, 2022
This change adds validation to reject an edge case where the
child_process API argument strings might contain null bytes
somewhere in between. Such strings were being silently truncated
before, so throwing an error should prevent misuses of this API.

Fixes: #44768
Signed-off-by: Darshan Sen <raisinten@gmail.com>
PR-URL: #44782
Reviewed-By: James M Snell <jasnell@gmail.com>
danielleadams pushed a commit that referenced this issue Dec 30, 2022
This change adds validation to reject an edge case where the
child_process API argument strings might contain null bytes
somewhere in between. Such strings were being silently truncated
before, so throwing an error should prevent misuses of this API.

Fixes: #44768
Signed-off-by: Darshan Sen <raisinten@gmail.com>
PR-URL: #44782
Reviewed-By: James M Snell <jasnell@gmail.com>
danielleadams pushed a commit that referenced this issue Jan 3, 2023
This change adds validation to reject an edge case where the
child_process API argument strings might contain null bytes
somewhere in between. Such strings were being silently truncated
before, so throwing an error should prevent misuses of this API.

Fixes: #44768
Signed-off-by: Darshan Sen <raisinten@gmail.com>
PR-URL: #44782
Reviewed-By: James M Snell <jasnell@gmail.com>
@LocutusOfBorg
Copy link

Hello @RaisinTen , looks like your test is not working on Ubuntu 23.04...
nodejs 18.13.0
https://launchpadlibrarian.net/644796275/buildlog_ubuntu-lunar-amd64.nodejs_18.13.0+dfsg-1ubuntu1_BUILDING.txt.gz
can you please doublecheck?

not ok 266 parallel/test-child-process-reject-null-bytes
  ---
  duration_ms: 0.272
  severity: fail
  exitcode: 1
  stack: |-
    node:assert:636
          throw err;
          ^
    
    AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
    + actual - expected
    
      Comparison {
        code: 'ERR_INVALID_ARG_VALUE',
    +   message: "The argument 'args[3]' must be a string without null bytes. Received 'BBB\\x00XXX'"
    -   message: /The argument 'args\[2\]' must be a string without null bytes/
      }
        at Object.<anonymous> (/<<PKGBUILDDIR>>/test/parallel/test-child-process-reject-null-bytes.js:88:1)
        at Module._compile (node:internal/modules/cjs/loader:1218:14)
        at Module._extensions..js (node:internal/modules/cjs/loader:1272:10)
        at Module.load (node:internal/modules/cjs/loader:1081:32)
        at Module._load (node:internal/modules/cjs/loader:922:12)
        at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
        at node:internal/main/run_main_module:23:47 {
      generatedMessage: true,
      code: 'ERR_ASSERTION',
      actual: TypeError [ERR_INVALID_ARG_VALUE]: The argument 'args[3]' must be a string without null bytes. Received 'BBB\x00XXX'
          at new NodeError (node:internal/errors:400:5)
          at validateArgumentNullCheck (node:child_process:968:11)
          at validateArgumentsNullCheck (node:child_process:975:5)
          at normalizeSpawnArguments (node:child_process:562:3)
          at spawn (node:child_process:750:13)
          at fork (node:child_process:170:10)
          at throws.code (/<<PKGBUILDDIR>>/test/parallel/test-child-process-reject-null-bytes.js:88:14)
          at getActual (node:assert:757:5)
          at throws (node:assert:903:24)
          at Object.<anonymous> (/<<PKGBUILDDIR>>/test/parallel/test-child-process-reject-null-bytes.js:88:1) {
        code: 'ERR_INVALID_ARG_VALUE'
      },
      expected: {
        code: 'ERR_INVALID_ARG_VALUE',
        message: /The argument 'args\[2\]' must be a string without null bytes/
      },
      operator: 'throws'
    }
    
    Node.js v18.13.0
  ...
ok 267 parallel/test-child-process-promisified

@LocutusOfBorg
Copy link

Maybe it has something to deal with the fact that we add --openssl-shared-config to some test?
+export TEST_CI_ARGS = --node-args="--openssl-shared-config"

+--- nodejs-18.7.0+dfsg.orig/test/parallel/test-tls-enable-keylog-cli.js
++++ nodejs-18.7.0+dfsg/test/parallel/test-tls-enable-keylog-cli.js
+@@ -18,7 +18,7 @@ tmpdir.refresh();
+ const file = path.resolve(tmpdir.path, 'keylog.log');
+ 
+ const child = fork(__filename, ['test'], {
+-  execArgv: ['--tls-keylog=' + file]
++  execArgv: ['--tls-keylog=' + file, "--openssl-shared-config"]
+ });
+ 
+ child.on('close', common.mustCall((code, signal) => {
+--- nodejs-18.7.0+dfsg.orig/test/parallel/test-tls-enable-trace-cli.js
++++ nodejs-18.7.0+dfsg/test/parallel/test-tls-enable-trace-cli.js
+@@ -19,7 +19,7 @@ if (!binding('tls_wrap').HAVE_SSL_TRACE)
+ 
+ const child = fork(__filename, ['test'], {
+   silent: true,
+-  execArgv: ['--trace-tls']
++  execArgv: ['--trace-tls', '--openssl-shared-config']
+ });
+ 
+ let stdout = '';

@LocutusOfBorg
Copy link

changing argv[2] to argv[3] seems to work as workaround, but we should have a smarter way to check if TEST_CI_ARGS have a different value other than the default...

@LocutusOfBorg
Copy link

--- nodejs-18.13.0+dfsg.orig/test/parallel/test-child-process-reject-null-bytes.js
+++ nodejs-18.13.0+dfsg/test/parallel/test-child-process-reject-null-bytes.js
@@ -87,7 +87,7 @@

 throws(() => fork(__filename, ['AAA', 'BBB\0XXX', 'CCC']), {
   code: 'ERR_INVALID_ARG_VALUE',
-  message: /The argument 'args\[2\]' must be a string without null bytes/
+  message: /The argument 'args\[3\]' must be a string without null bytes/
 });

 throws(() => spawn(process.execPath, [__filename, 'AAA', 'BBB\0XXX', 'CCC']), {

This works as specific Ubuntu workaround.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
child_process Issues and PRs related to the child_process subsystem.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants