Skip to content

Commit

Permalink
domain: make node resilient to Array prototype tempering
Browse files Browse the repository at this point in the history
Fixes: #36669

PR-URL: #36676
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
aduh95 authored and danielleadams committed Jan 12, 2021
1 parent 94afc3e commit 9b9b6d5
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 1 deletion.
2 changes: 1 addition & 1 deletion lib/domain.js
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ Domain.prototype.exit = function() {
// Exit all domains until this one.
ArrayPrototypeSplice(stack, index);

exports.active = stack[stack.length - 1];
exports.active = stack.length === 0 ? undefined : stack[stack.length - 1];
process.domain = exports.active;
updateExceptionCapture();
};
Expand Down
66 changes: 66 additions & 0 deletions test/parallel/test-repl-array-prototype-tempering.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const { spawn } = require('child_process');

const replProcess = spawn(process.argv0, ['--interactive'], {
stdio: ['pipe', 'pipe', 'inherit'],
windowsHide: true,
});

replProcess.on('error', common.mustNotCall());

const replReadyState = (async function* () {
let ready;
const SPACE = ' '.charCodeAt();
const BRACKET = '>'.charCodeAt();
const DOT = '.'.charCodeAt();
replProcess.stdout.on('data', (data) => {
ready = data[data.length - 1] === SPACE && (
data[data.length - 2] === BRACKET || (
data[data.length - 2] === DOT &&
data[data.length - 3] === DOT &&
data[data.length - 4] === DOT
));
});

const processCrashed = new Promise((resolve, reject) =>
replProcess.on('exit', reject)
);
while (true) {
await Promise.race([new Promise(setImmediate), processCrashed]);
if (ready) {
ready = false;
yield;
}
}
})();
async function writeLn(data, expectedOutput) {
await replReadyState.next();
if (expectedOutput) {
replProcess.stdout.once('data', common.mustCall((data) =>
assert.match(data.toString('utf8'), expectedOutput)
));
}
await new Promise((resolve, reject) => replProcess.stdin.write(
`${data}\n`,
(err) => (err ? reject(err) : resolve())
));
}

async function main() {
await writeLn(
'Object.defineProperty(Array.prototype, "-1", ' +
'{ get() { return this[this.length - 1]; } });'
);

await writeLn(
'[3, 2, 1][-1];',
/^1\n(>\s)?$/
);
await writeLn('.exit');

assert(!replProcess.connected);
}

main().then(common.mustCall());

0 comments on commit 9b9b6d5

Please sign in to comment.