patriksimek/vm2

VMError: Operation not allowed on contextified object

ppedziwiatr opened this issue · 5 comments

Hey,

I'm getting VMError: Operation not allowed on contextified object
image

while trying to run some untrusted code.

The code that fails is:

function createBuffer(that, length) {
    if (kMaxLength() < length) {
      throw new RangeError("Invalid typed array length");
    }
    if (Buffer2.TYPED_ARRAY_SUPPORT) {
      that = new Uint8Array(length);
      that.__proto__ = Buffer2.prototype; // this line fails!
    } else {
      if (that === null) {
        that = new Buffer2(length);
      }
      that.length = length;
    }
    return that;
  }

VM2 configuration:

const vm = new vm2.NodeVM({
          console: 'off',
          sandbox: {
            SmartWeave: swGlobal,
            BigNumber: BigNumber,
            logger: this.logger,
            ContractError: ContractError,
            ContractAssert: function (cond, message) {
              if (!cond) throw new ContractError(message);
            },
            //https://github.com/patriksimek/vm2/issues/484#issuecomment-1327479592
            Uint8Array: Uint8Array,
            atob: atob
          },
          compiler: 'javascript',
          eval: false,
          wasm: false,
          allowAsync: true,
          wrapper: 'commonjs'
        });

This is expected and wanted. Changing the prototype of host objects if forbidden.

Oh...right...so - with no other workaround with working with Uint8Array than #484 (comment) - there's effectively no way to run this code in VM2, right?

What you could try is:

const ProxiedUint8Array = new Proxy(Uint8Array, {
	construct(target, args, newTarget) {
		const original = Reflect.construct(target, args, newTarget);
		Reflect.defineProperty(original, '__proto__', {
			get() {return Reflect.getPrototypeOf(original);},
			set(value) {Reflect.setPrototypeOf(original, value);},
			configurable: true,
			enumerable: false
		});
		return original;
	}
});

const vm = new NodeVM({sandbox: {
	Uint8Array: ProxiedUint8Array
}});

Thanks, we will give it a try!

This ends with:

'TypeError: Method get TypedArray.prototype.length called on incompatible receiver [object Object]\n' +
    '    at TypedArray.get length [as length] (<anonymous>)\n' +
    '    at get (<anonymous>)\n' +
    '    at VM2 Wrapper.get (/Users/piotrpedziwiatr/projects/redstone-smartcontracts/node_modules/vm2/lib/bridge.js:447:11)\n' +
    '    at get (<anonymous>)\n' +
    '    at VM2 Wrapper.get (/Users/piotrpedziwiatr/projects/redstone-smartcontracts/node_modules/vm2/lib/bridge.js:447:11)\n' +
    '    at get (<anonymous>)\n' +
    '    at VM2 Wrapper.get (/Users/piotrpedziwiatr/projects/redstone-smartcontracts/node_modules/vm2/lib/bridge.js:447:11)\n' +
    '    at Proxy.write (vm.js:1337:25)\n' +
    '    at fromString (vm.js:404:23)\n' +
    '    at from (vm.js:364:14)'
``` ...