Skip to content

Commit 16fcfb4

Browse files
committed
benchmark: protect against accidental fork bomb
Signed-off-by: James M Snell <jasnell@gmail.com> Assisted-by: Opencode
1 parent 3b515c2 commit 16fcfb4

1 file changed

Lines changed: 30 additions & 1 deletion

File tree

‎benchmark/common.js‎

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,21 @@ class Benchmark {
198198
}
199199

200200
_run() {
201+
// A forked child is told to run the benchmark function directly, rather
202+
// than build its own queue and fork again, through the
203+
// NODE_RUN_BENCHMARK_FN environment variable. A child always inherits
204+
// this.flags in its execArgv, so reaching _run() with those flags already
205+
// applied means the variable did not survive to the child and every
206+
// generation would keep forking. Fail loudly instead of forking forever.
207+
if (process.send &&
208+
this.flags.length > 0 &&
209+
this.flags.every((flag) => process.execArgv.includes(flag))) {
210+
throw new Error(
211+
'Benchmark child process was started with the benchmark flags but ' +
212+
'without NODE_RUN_BENCHMARK_FN, refusing to fork again. Something ' +
213+
'removed the variable from the child environment.');
214+
}
215+
201216
// If forked, report to the parent.
202217
if (process.send) {
203218
process.send({
@@ -213,6 +228,20 @@ class Benchmark {
213228
this.originalOptions.setup(this.queue);
214229
}
215230

231+
// Enforcing the permission model removes the environment variables
232+
// --allow-env does not grant access to at startup, which would drop the
233+
// NODE_RUN_BENCHMARK_FN set below. The child only ever sees the
234+
// environment this process hands it, so granting access to all of it does
235+
// not widen what the benchmark can reach. Audit mode removes nothing, so
236+
// it is left alone to keep its diagnostics intact.
237+
const childExecArgv = this.flags.concat(process.execArgv);
238+
const enforcesPermission = (arg) =>
239+
arg === '--permission' || arg.startsWith('--permission=');
240+
if (childExecArgv.some(enforcesPermission) &&
241+
!childExecArgv.some((arg) => arg.startsWith('--allow-env'))) {
242+
childExecArgv.push('--allow-env=*');
243+
}
244+
216245
const recursive = (queueIndex) => {
217246
const config = this.queue[queueIndex];
218247

@@ -233,7 +262,7 @@ class Benchmark {
233262

234263
const child = child_process.fork(require.main.filename, childArgs, {
235264
env: childEnv,
236-
execArgv: this.flags.concat(process.execArgv),
265+
execArgv: childExecArgv,
237266
});
238267
child.on('message', sendResult);
239268
child.on('close', (code) => {

0 commit comments

Comments
 (0)