Promises allow vm.runInContext timeout to be escaped #3020
Description
The timeout property on many of the vm module's functions isn't completely foolproof. In the following example, some sandboxed code executed by vm.runInNewContext with a timeout of 5ms schedules an infinite loop to run after a promise resolves, and then synchronously executes an infinite loop. The synchronous infinite loop is killed by the timeout, but then the scheduled loop fires and never ends.
vm.runInNewContext(
'Promise.resolve().then(()=>{while(1)console.log("foo", Date.now());}); while(1)console.log(Date.now())',
{console:{log(){console.log.apply(console,arguments);}}},
{timeout:5}
);
Some output:
1442966735705
...
1442966735710
1442966735710
1442966735710
1442966735710
1442966735710
Error: Script execution timed out.
at Error (native)
at ContextifyScript.Script.runInNewContext (vm.js:18:15)
at Object.exports.runInNewContext (vm.js:49:17)
at repl:1:4
at REPLServer.defaultEval (repl.js:164:27)
at bound (domain.js:250:14)
at REPLServer.runBound [as eval] (domain.js:263:12)
at REPLServer.<anonymous> (repl.js:392:12)
at emitOne (events.js:82:20)
at REPLServer.emit (events.js:169:7)
> foo 1442966735715
foo 1442966735716
foo 1442966735716
foo 1442966735716
foo 1442966735716
... [continues forever]
I'm not really sure what a good solution for this would be, if it's possible, and whether the vm module intends to stand up to this sort of thing. At the very least I think vm's docs should have a note that the timeout property works by best-effort or something and isn't completely foolproof, so no one thinks it's safe to try to use it to sandbox user code in a guaranteed timely manner.
Activity