On running some Wasm contracts with LLVM, specifically for EVM

Fascinating! I did more research here, and here’s what I’ve found:

wasmer indeed uses wasm-level instrumentation, and not vm-level instrumentation, as I originally thought. That is, they inject a wasm global, and instrument the code to decrement this global in every basic block.

However, I believe that wasm spec guarantees that this instrumentation approach is safe and not abusable. The only way to wasm global variable from within wasm code is via global.set|get instructions, which take the index of a global as a compile-time constant. That the constant denotes existing global of the correct type is checked at module validation time. Instrumentation adds a new global, after the module has been validated. Unlike functions, there’s no equivalent to call_indirect instruction for accessing a global, determined at runtime.

I haven’t found an official super-direct statement claiming that this is safe, but:

  • wasm security document mentions that locals and globals are accessible only via indexes
  • spec mentions that globals are accessible only via global.get|set instructions
  • ctrl+f in the instructions document doesn’t reveal any additional ways to access the global

So, this instrumentation is safe in principle, although I haven’t verified that its bug free.

The only hazard I see here (pointed out by @olonho) is that some future version of wasm will add instructions for indirect access to global. I don’t think this is a real problem: the fact that locals & globals are managed is a part of security model; indirect access is not necessary a problem – indirect acesses go via table, and it’s possible to verify that a specific entity is not escaped via a table; in the hypothetical case where instruction is added to lookup arbitrary global by raw index, we can refuse to run contacts with this particular insturction.

1 Like