Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node JavaScript contexts sharing built-in prototypes?

When creating a new context with Node's vm.runInNewContext, are built-in (Object, Function, etc.) prototypes shared or not?

Documentation on runInNewContext says:

Running code does not have access to local scope and the object sandbox will be used as the global object for code.

Is Object.prototype in the global scope, hence not shared?

In node_script.cc:338-345 and node_script.cc:403-409 I see it's referencing the objects, so are those objects, from sandbox, using the Object.prototype of the parent context which calls vm.runInNewContext and objects created in the new context using a different Object.prototype?

(Note: vm module is a maze: vm module -> evals process.binding -> node_script.cc source)

like image 903
Pindatjuh Avatar asked Dec 27 '22 21:12

Pindatjuh


2 Answers

As far as I know the code is run in a completely new context, with different global constructors for Object, Array, etc.

Object.prototype.a = function() { console.log('hello'); };
({}).a(); // 'hello'
require('vm').runInNewContext('({}).a();'); // should throw

I don't think it would really be a new context if Object::a had access to variables in the original context.

This has some implications though:

vm.runInNewContext('[];') instanceof Array; // returns false

Because that array was created with a completely different constructor, the instanceof operator will be affected.

like image 72
chjj Avatar answered Jan 09 '23 03:01

chjj


Conclusion

Inside a vm.runInNewContext, there are two Object.prototypes: one that is created inside the new context and one that is referencing to the parent context, via the sandbox. Apparently, Node has set the security tokens correctly, so contexts are allowed to access the parent's objects.

Is Object.prototype in the global scope, hence not shared?

It is not in the global scope, but in the context. It's not shared.

In node_script.cc:338-345 and node_script.cc:403-409 I see it's referencing the objects, so are those objects, from sandbox, using the Object.prototype of the parent context which calls vm.runInNewContext and objects created in the new context using a different Object.prototype?

Yes.

When creating a new context with Node's vm.runInNewContext, are built-in (Object, Function, etc.) prototypes shared or not?

Not shared.

The test

// Test

var vm = require('vm');

var parentLog = function(message) {
    process.stdout.write(message + "\n");
}

Object.prototype.test = "[parent Object.prototype.test]";

var parentObject = new String("[parent parentObject]");

var parentSandbox = {
    log: parentLog,
    testObject: parentObject,
};

var parentCode =
    "log('vm testObject: ' + testObject);" +
    "log('vm testObject.test: ' + testObject.test);" +
    "log('vm create Object.prototype.test');" +
    "Object.prototype.test = '[vm Object.prototype.test]';" +
    "log('vm Object.prototype.test: ' + Object.prototype.test);" +
    "log('vm testObject.test: ' + testObject.test);";

parentLog('pre-parent parentObject: ' + parentObject);
parentLog('pre-parent parentObject.test: ' + parentObject.test);
parentLog('pre-parent Object.prototype: ' + Object.prototype.test);

var parentScript = vm.createScript(parentCode, "<test>");
parentScript.runInNewContext(parentSandbox);

parentLog('post-parent parentObject: ' + parentObject);
parentLog('post-parent parentObject.test: ' + parentObject.test);
parentLog('post-parent Object.prototype: ' + Object.prototype.test);

Output:

pre-parent parentObject: [parent parentObject]
pre-parent parentObject.test: [parent Object.prototype.test]
pre-parent Object.prototype: [parent Object.prototype.test]
vm testObject: [parent parentObject]
vm testObject.test: [parent Object.prototype.test]
vm create Object.prototype.test
vm Object.prototype.test: [vm Object.prototype.test]
vm testObject.test: [parent Object.prototype.test]
post-parent parentObject: [parent parentObject]
post-parent parentObject.test: [parent Object.prototype.test]
post-parent Object.prototype: [parent Object.prototype.test]
like image 37
Pindatjuh Avatar answered Jan 09 '23 02:01

Pindatjuh