Skip to content

Commit 67903b0

Browse files
committed
child_process: validate arguments for null bytes
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: #44768 Signed-off-by: Darshan Sen <raisinten@gmail.com>
1 parent a50e7c5 commit 67903b0

File tree

2 files changed

+28
-0
lines changed

2 files changed

+28
-0
lines changed

lib/child_process.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const {
3939
ObjectPrototypeHasOwnProperty,
4040
RegExpPrototypeExec,
4141
SafeSet,
42+
StringPrototypeIncludes,
4243
StringPrototypeSlice,
4344
StringPrototypeToUpperCase,
4445
} = primordials;
@@ -734,6 +735,7 @@ function abortChildProcess(child, killSignal) {
734735
*/
735736
function spawn(file, args, options) {
736737
options = normalizeSpawnArguments(file, args, options);
738+
validateArgumentsNullCheck(options.args);
737739
validateTimeout(options.timeout);
738740
validateAbortSignal(options.signal, 'options.signal');
739741
const killSignal = sanitizeKillSignal(options.killSignal);
@@ -818,6 +820,10 @@ function spawnSync(file, args, options) {
818820

819821
debug('spawnSync', options);
820822

823+
// Validate the arguments for null bytes. The normalizeSpawnArguments()
824+
// function already makes sure that the array is present.
825+
validateArgumentsNullCheck(options.args);
826+
821827
// Validate the timeout, if present.
822828
validateTimeout(options.timeout);
823829

@@ -949,6 +955,15 @@ function execSync(command, options) {
949955
}
950956

951957

958+
function validateArgumentsNullCheck(args) {
959+
for (let i = 0; i < args.length; ++i) {
960+
if (StringPrototypeIncludes(args[i], '\u0000')) {
961+
throw new ERR_INVALID_ARG_VALUE('args', args, 'cannot contain null bytes');
962+
}
963+
}
964+
}
965+
966+
952967
function validateTimeout(timeout) {
953968
if (timeout != null && !(NumberIsInteger(timeout) && timeout >= 0)) {
954969
throw new ERR_OUT_OF_RANGE('timeout', 'an unsigned integer', timeout);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
'use strict';
2+
require('../common');
3+
4+
// Regression test for https://github.com/nodejs/node/issues/44768
5+
6+
const { throws } = require('assert');
7+
const { spawn, spawnSync } = require('child_process');
8+
9+
throws(() => spawn(process.execPath, [__filename, 'AAA', 'BBB\0XXX', 'CCC']),
10+
{ code: 'ERR_INVALID_ARG_VALUE' });
11+
12+
throws(() => spawnSync(process.execPath, [__filename, 'AAA', 'BBB\0XXX', 'CCC']),
13+
{ code: 'ERR_INVALID_ARG_VALUE' });

0 commit comments

Comments
 (0)