Wasmer 3.0
wasmer.io
wasmer.io
> In Wasmer 3.0 we used the power of Zig for doing cross-compilation from the C glue code into other machines.
> This made almost trivial to generate a [binary] for macOS from Linux (as an example).
> So by default, if you are cross-compiling we try to use zig cc instead of cc so we can easily cross compile from one machine to the other with no extra dependencies.
https://wasmer.io/posts/wasm-as-universal-binary-format-part...
> Using the wasmer compiler we compile all WASI packages published to WAPM to a native executable for all available platforms, so that you don't need to ship a complete WASM runtime to run your wasm files.
https://wasmer.io/posts/wasm-as-universal-binary-format-part...
Do you have a source for this claim? Using a JIT with AOT binaries (which is what this seems to be) can sometimes be very beneficial. It's like doing PGO without the manual work of doing PGO properly.
I'm sure the JIT can make poor decisions sometimes, but I would want to see a comprehensive set of benchmarks, like The Benchmarks Game and TechEmpower showing this. Benchmarks aren't always reflective of reality, but good ones are usually more insightful than random opinions.
The only Wasmer benchmarks I could readily find were from three years ago, and that was before Wasmer 1.0, let alone 3.0.
EDIT: Reading more... maybe `create-exe` doesn't include the JIT at all, so it is just making an AOT binary from the source WASM? In which case, benchmarks are just as necessary to understand how it affects performance compared to a normally-compiled native binary.
I also think of WASM as a tool that could provide a useful security boundary.
$ make wasm
$ wasmer create-exe tpl.wasm -o tpl-wasm
$ time ./tpl-wasm --consult < tak.pl -g 'time(run)' --ns
'<https://josd.github.io/eye/ns#tak>'([34,13,8],13).
% Time elapsed 1.39s
real 0m1.403s
user 0m1.333s
sys 0m0.070s
$ time tpl tak.pl -g 'time(run)' --ns
'<https://josd.github.io/eye/ns#tak>'([34,13,8],13).
% Time elapsed 0.448s
real 0m0.473s
user 0m0.463s
sys 0m0.010s
WASM is about 3x slower. In general I've found it to be 2-3x slower, at least for my use cases. I also tried the LLVM compiler instead of Cranelift but it was slightly slower.That benchmark looks too short to be a useful measure of how JIT influences performance, otherwise I would ask how the regular Wasmer does in that benchmark too (since it seems like create-exe doesn't include a JIT).
I believe it's a bytecode but I know that function pointers are involved at least with the built-in predicates (see predicates.c).
My reading of the numbers is that the startup overhead is about 13ms in my example, quite fast. Shout out to Wizer for greatly reducing the startup time.
Which do you think is more important for non-developers?
Aside, I also can't believe I'm defending server side rendering in this day and age where people actually think client side routing is better. Around 10 years ago when React was still getting new, I would have held the same views as you. It's interesting how tech moves cyclically.
Write a library in Rust and compile it to WASM, theoretically any language with WASM bindings could run it.
This could really make niche languages more easily adopted if their execution environment supported libraries in WASM.
Imagine using Java's JDBC from something like Nim. Nim could take advantage of a 30 year old mature and fast database access framework without haveing to envest that ime and effort themselves.
Or even something more modern like the polars dataframe library.
You can already do this with JNI. How does WASM improve things? In both cases (WASM or native code) you get the overhead of two runtimes and the hassle of converting data types, don't you?
> Most languages have a way to run on a wasm engine
But it is basically useless for managed languages that as of yet has to bring their runtimes as well.
It's often the case that people choose languages based on the availability of the libraries written in those languages. The goal of non-browser WASM is to get rid of that and to minimize the friction of inter-language communication, so you don't have to rewrite it in $language. WASM is not tied to any language (like the JNI).
Here's an example where performance wouldn't matter as much:
Let's say I'm the author of a programming language and I want to add a db layer to my standard lib.
Via WASM I can use a working backend while I'm protyping the API for my db layer. If the performance isn't fast enough I can start implementing my own "native" version with feature parity.
I can then use some of the tests from the original library (via WASM) to make sure my implementation has feature parity to the original.
For performance, we ship three compiler backends: LLVM (fast execution, but slowest compilation), cranelift and singlepass (our own compiler, very fast compilation and you can compile untrusted code - but slowest execution). There is a slowdown, but the goal is to keep that at a minimum (proper performance tracking is on the bucket list). We are pre-compiling the python.wasm (which was already pre-optimized when the compilation to WASM happened) with LLVM, so you should get assembly that is very close to the native execution, with the exception of the necessary VM overhead. The goal is to make it so that the interoperability gains are worth the performance hit.
A bit of a rant, but there's nothing specific to WebAssembly about this.
Whether you're using WebAssembly or native code:
- The basic interface you get between caller and callee is a low-level calling convention, where essentially all you have are integers (which can be pointers), and any higher-level data structures need to be built out of that.
- A slightly higher-level interface is the C ABI; many languages support exporting and consuming APIs using the C ABI, but it can be frustratingly low-level.
- To provide an even higher-level interface, there are bindings generators, which could in principle either be designed as direct language-to-language bridges, or as a single common standard that any language can provide and consume APIs for.
The WebAssembly Component Model standard and the wit-bindgen tool are an example of the latter. They happen to be defined specifically for WebAssembly rather than generically for any architecture. If they become ubiquitous at some point in the future like they're supposed to, then WebAssembly will have an advantage when it comes to high-level bindings, not because of any fundamental technical aspect of WebAssembly itself, but just because people building these bindings on top of WebAssembly have more motivation and more consensus. (WebAssembly does have a technical advantage when it comes to sandboxing between components, but this is relatively unimportant for most use cases.)
But for now, wit-bindgen isn't ubiquitous, and most of those languages don't even work in WebAssembly yet…
Sandboxing also goes a long way towards containing the supply chain security issues that every language is susceptible to.
Native code might assume that code it calls won’t misbehave in these ways, but wasm guarantees it, and that allows wasm VMs which run untrusted code to have more efficient implementations.
Small remark: There is nothing like "the C ABI".
https://faultlore.com/blah/c-isnt-a-language/#c-doesnt-actua...
What you're saying is completely impossible right now AFIK…
Why not? You still need operations like "create object", "look up method", "invoke method", "convert type between languages" etc. WASM doesn't have any kind of polyglot layer that does this automatically.
Ironically, Graal/Truffle actually do. There's a whole infrastructure where languages can expose their structures, functions, objects etc via a language-neutral in-process protocol and the compiler understands how to optimize across the transitions, so you can actually load JavaScript into Python and do those sorts of things:
https://www.graalvm.org/latest/reference-manual/polyglot-pro...
The API you use to import code from other languages is standardized, so it doesn't matter what language the other side is using. But WASM doesn't do anything like that.
"with wasm, you just pull in csharp.wasm, python.wasm and java.wasm, so it's just one binding layer, not three"
Are these real files/projects you're talking about here? If so, can you show us these things? Because WASM seems far too low level to define a Truffle-like polyglot layer let alone make it fast.
this misses the fact that (unless I'm wrong), WASM by itself can't really do anything like file system/network operations
I know that's not the main usecase of where to put WASM logic that needs to be performant (it's the opposite really)
I just think it's worth calling out that a WASM library really can't do much from what I understand. Like... basic math? You have to supply it (through a WASM runtime) interop to other functions it can call... I think?
Would love to be taught/proven wrong.
I absolutely disagree with ASC's stance on this, but it seems that the AssemblyScript project at least wants nothing to do with that kind of thing:
[1] https://devclass.com/2022/09/08/assemblyscript-project-wasi-...
[2] https://www.assemblyscript.org/standards-objections.html
> Languages that would naturally fit the Web platform not only are overlooked, but WASI's self-imposed abstinence of Web concepts undermines other languages' interoperability potential with JS and the Web platform specifically.
The problem is that objectively, the web platform is garbage. Half-baked, weirdly incomplete abstractions, most of can only be rationally explained as either historical accidents or the aftermath of political fights on standards committees. Why would anyone base a new abstraction around those if they don't strictly have to?
WASI is trying to be a cross language API for use by multiple languages that target WASM. But the author wants this API to more closely follow existing JS conventions? Sure that's useful to JS/Web, but it's not useful for anyone else trying to target WASM with a language that's not JS. And if you want to target Web API's with JS, can't you already just write native JS?
Bikeshedding over string encoding for example and objecting to WASI's promotion of UTF-8 because it doesn't match the encoding used by JS.
Say I write a Rust program to use `reqwest` to make a HTTP request to some API that is going to return me JSON.
I can compile it to... ELF with Rust I guess on Linux, or I can use Rust to compile it to:
> wasm32-wasi - when using wasmtime this is likely what you'll be using. The WASI target is integrated into the standard library and is intended on producing standalone binaries.
> wasm32-unknown-unknown - this target, like the WASI one, is focused on producing single .wasm binaries. The standard library, however, is largely stubbed out since the "unknown" part of the target means libstd can't assume anything. This means that while binaries will likely work in wasmtime, common conveniences like println! or panic! won't work.
> wasm32-unknown-emscripten - this target is intended to work in a web browser and produces a .wasm file coupled with a *.js file, and it is not compatible with wasmtime.
Say the Tokio async runtime works for wasm32-wasi (I don't think it does currently, I could be wrong) and reqwest + all of its network dependencies compile to wasm32-wasi (not sure if they do, I think there is progress) and say lite-json or some kind of JSON de-serizaliation works
Why would I compile + run as wasm32-wasi instead of stable-x86_64-unknown-linux-gnu?
Interesting links:
https://github.com/tokio-rs/tokio/issues/4827 - tokio support
https://github.com/async-rs/async-std/issues/505 - async-std support
https://www.reddit.com/r/rust/comments/h9bakg/could_not_find... - > There's no blocking implementation available for WASM. The WASM backend uses HTML APIs (fetch) and is supposed to run in a browser, where you can't block the event loop
After looking at the objections from these guys, they seem to boil down to, "but it makes non-web development more viable again, and that's bad for the web". The first part is true. The second part is arguable, but IMO if it is true, then balance needs to be restored.
Lmao. The guy is just mad that WASI uses utf-8, as opposed to utf-16 (which is what Javascript uses)
this has 7 weekly downloads... I would expect more?
So 7 weekly downloads sounds about right for an unknown package that is slower.
https://hacks.mozilla.org/2021/12/webassembly-and-back-again...
It's also useful in "plugin" scenarios, like say filtering code in a network proxy. Or if you wanted to make your own Function as a Service system.
Think about a workflow engine embedded in a marketing product. Usually there's some kind of GUI builder which generates an AST to be interpreted directly at runtime. What if instead the GUI generated a WASM artifact to be run on sandboxed runtimes?
What if, furthermore, you offered advanced users the opportunity to upload WASM binaries where they could implement arbitrarily complex logic to be executed in the sandbox?
I think this is a super powerful concept, although of course making a business case for implementing it is the trick.
The use case is essentially user logic for event stream processing, where the events are things like "received an email" or "clicked a link" or "3 days have passed". You're not going to spin up a KVM for every contact on a 2 million member email list even if you're using Firecracker, but executing a WASM blob for every event might be feasible.
wasm gives you the bare minimum to run, other projects fill the gaps between that and what you would normally expect for an execution environment (ABIs, file system access, stacks, etc...). wasmer is one of such projects.
Web standards/technologies are in wide use outside of browsers (via things like Electron), so you may find that the name makes more sense when viewed through that lens.
Do you have any additional details/links on how this works?
https://docs.flightsimulator.com/html/Programming_Tools/WASM...
For instance I have a C++ shader compiler which includes some massive 3rd party libraries (glslangValidator, SPIRVTools and SPIRVCross) which takes forever to compile, so distributing in source code form is not really an option, and the only alternative is to ship precompiled binaries for each supported OS/CPU combination. Currently I do this via GH Actions, which kinda works, but just building a single WASM blob and shipping that to users (who then would need to install one of the WASM runtimes though) sounds kinda interesting.
PS: WASM may also be useful as universal plugin format. For instance the new Microsoft flight sim uses WASM instead of scripting or native DLLs for modding:
https://docs.flightsimulator.com/html/Programming_Tools/WASM...
The documentation is a bit unclear about this, but there's this weird blurb at the end:
> Note: LLVM bitcode is platform-dependent. The program must be compiled to bitcode for an appropriate platform.
...why would this detail even matter if LLVM bitcode is converted to 'GraalVM bytecode'? In any case, it doesn't sound much like "write once run everywhere" ;)
I have yet to get my feet wet with sulong, but my guess would be that LLVM will produce different bitcode on different platforms, and thus the execution can potentially be different - also note that llvm bitcode is not a stable format. But I don’t think that interpreting it on a different platform than it was compiled on would have a fundamental reason not to work (after all, it is just java code) - perhaps it uses the platform llvm libs for some parsing, which is not platform-agnostic?
> Overall JVM or CLR always seemed too heavyweight for many use cases.
The most common implementation may be; there are plenty of tiny jvms, some target embedded devices even.
1. Well supported by a company and a community
2. Are they free?
Especially 2, it sounds ridiculous but frankly even huge corps just use free stuff whenever they can.
Java was invented as IoT technology in the first place. Long before this acronym even existed.
It run on all the old 4-line monochrome text display dumb phones.
Java runs on SmartCards.
The question is—as always—how efficient this is.
But this goes also the other way around.
Even you can in theory run arbitrary languages on a WASM runtime the question how efficient this is stands also!
And in fact running anything else than "C languages" in WASM is at least as inefficient as running "C languages" on the JVM…
Hell, it is a really safe bet to say that running a C-like program on the JVM is much much faster than porting a whole runtime (which is very performance-oriented) on top of a runtime and make it run some code. Wasm simply can’t expose the optimizations runtimes routinely make use of (template interpreters for example))
I wanted only to point out that using the word "even" in the cited part is kind of "funny". Because this was actually the originally intended usage of Java.
It was invented as safe replacement of C/C++ especially for embedded development. (But now, sure, it ended up on the really huge boxes in DCs).
It offered of course also the possibility to blacklist everything by default.
The problem with such a granular sandbox is that it's too complex for most use cases.
When you need to whitelist any and every call to the outside world this becomes very tedious.
That's why Java now removes the sandbox…
https://inside.java/2021/04/23/security-and-sandboxing-post-...
Let's see how this works out for WASM.
I guess: Without resorting to using some language(s) with build-in support for capability security a whitelist based sandbox approach won't ever work without issues.
First of all you can forget about C/C++. Everything in this languages assumes free access to the system.
Rust does not have any support for capabilities either (yet, and for the years to come at least).
The best current WASM sandbox implementation, which is in WasmTime not Wasmer, is not more than a FS block. (And the memory safety guaranties you get in any VM language, of course).
https://docs.wasmtime.dev/security.html
I don't find any such feature mentioned in the Wasmer docs. It seems completely without any sandbox! (To stress it once more: All VM languages are memory safe. That's not sandboxing. All the "sandboxed by default" claims are misleading, at least).
https://github.com/wasmerio/wasmer/issues/221
That even people here on HN believe in the currently unfulfilled WASM security promises shows only how good the WASM marketing is. This should make you even more skeptical. One should never over promise on security! Java had to learn this the hard way over many years (as their sandbox had have holes in the past, and was also almost impossible to correctly configure).
That's not correct. Wasmer aims to be a fully sandboxed WebAssembly Runtime. Wasmer WASI implementation is also fully sandboxed.
Could you please link to some authoritative documentation for that?
As I said I don't see this in any docs or GitHub sources.
The point is: It's irrelevant what they "aim for". The only interesting thing at the moment is the status quo.
https://github.com/wasmerio/wasmer/blob/master/lib/wasi/READ...
I still don't get it.
What does "the aim to be 'fully sandboxed'" mean in the light of "support [of] standard I/O, file I/O, filesystem manipulation, memory management, time, string, environment variables, program startup etc."?
What are "secure systemcalls"? What does this mean on the technical level?
How is the simple FS access filter (something you get form std. Unix FS access rights since 50 years) something special here, or even considered "fully sandboxed"?
(I get the broader idea of capabilities. But I would see this only as a minor implementation detail in the current state).
Let me explain a bit more how:
* stdio / file io: thanks to Wasmer VFS and the WASI mapped dirs, the application will only able to access to the directories explicitly defined by the user when running a program. Any file/dir access outside of the allowed directories will throw an error (both by design of WASI and by our implementation of it). Note: by default stdout/stderr will be piped but that can also be easily customized.
* Environment variables: no environment variables can be accessed unless explicitly specified to our CLI (or SDKs)
* Time: we consider time access (get) to be harmless (WASI don't allow setting the platform/OS time, so we don't have to worry about that)
> What are "secure systemcalls"? What does this mean on the technical level?
It means system calls that we consider harmless to execute. For example, getting the current time (unix timestamp) is considered harmless by our WASI implementation (it should be easy to even shield that, if needed), but accessing a file could be harmful (that's why we ask for permission first).
Of course, no software is free from bugs that could jailbreak the sandbox, specially after Spectre and Meltdown. So having something to be "fully sandboxed" is an infinite game.
But our aim is there, nonetheless :)
> Basically, what we mean by sandboxed is that the application would not be able to do anything harmful to your system unless explicitly allowed (similar ethos as Deno, compared to NPM).
So how is this different to the mentioned (obviously failed) JVM sandbox?
It's exactly the same concept as I see it. "Security" fully depends on (complex!) configuration.
What possibly could go wrong here…
> stdio / file io: thanks to Wasmer VFS and the WASI mapped dirs, the application will only able to access to the directories explicitly defined by the user when running a program. Any file/dir access outside of the allowed directories will throw an error (both by design of WASI and by our implementation of it). Note: by default stdout/stderr will be piped but that can also be easily customized.
So basically you've implemented file access rights.
With multiple additional layers of indirection and a lot of additional code. (TCB anybody?)
Sure, this looks very promising and innovative. What possibly could go wrong here?
How does this prevent unwanted information exfiltration given std. I/O and networking works?
Also, how does it prevent that a rouge / hacked app for example encrypts all files / databases it has regular access to?
> Environment variables: no environment variables can be accessed unless explicitly specified to our CLI (or SDKs)
> Time: we consider time access (get) to be harmless (WASI don't allow setting the platform/OS time, so we don't have to worry about that)
How is this different form std. Linux "capabilities", and the Linux syscall filter?
> Of course, no software is free from bugs that could jailbreak the sandbox, specially after Spectre and Meltdown. So having something to be "fully sandboxed" is an infinite game.
Getting the sandbox tight and close is not the problem imho.
This was done several times already (with mostly OK-ish results).
The problems start when you need to dig holes into it. (And you need holes, otherwise you're so "secure" that you can't do anything meaningful).
I still don't get how a new "whitelist only" sandbox will not end up in the same fundamental issue like the ones before it. When "security" is crucially depended on complex configuration it's very likely that there will be unintended holes because someone didn't get the config right. (Just think about why almost nobody is using SELinux even it gives you even better guaranties then WASM currently).
Java shows this problem also very well: It died on the client not because there were technical loopholes in the sandbox. There were almost none of this kind! The problem was the overly complex sandbox config (with to be honest additionally quite stupid defaults in the beginning) that nobody got right, and security issues popped up constantly therefore.
So you don't even need to think about Spectre and Meltdown kind of attack vectors.
After years (or even decades) there is still no guaranty that people get things like Linux "capabilities" or even std. FS access rights correct. Now the same people are expected to get some other features, that do basically the same, right?
I know already how this will end up… And this will blow up very painfully right into your face after you have spit so much promises about the superior security of your approach!
Don't be stupid, learn form the Java story. (And no, you're not anyhow better. If you think that, you lost already, and your ship is going to sink with a lot of skit for sure).
---
I think the only way to get capability security right, and especially usable by mere mortals in the first place is to make it a fundamental part of the languages used.
Rust is light years away form that, though… (And others don't even have the basic enabling features for that.)
The languages that tried something like that in the past are by now dead since a long time. (Like the E programming language)
Though I put high hopes into the upcoming Scala features in this regard.
But nevertheless those are way ahead of any other (real) language even there a usable system is also still years away. For reference:
https://docs.scala-lang.org/scala3/reference/experimental/cc...
(This will give you all the features of Rust plus true capabilities in the type system. But not before the next couple of years. But maybe someone starts to clone this feature set early so they won't be a decade behind when Scala finally ships this… ;-))
> whitelist any and every call
This is the default WASM model. It provides no outside calls by default. This works fine for the original web browser model where WASM is essentially just providing a way to run a function from JS with near native speed. It's extremely limited in usefulness but fast and secure.
WASI is an effort to provide a set of curated APIs to make it easier to use WASM for more use cases like networking or even printing to a console.
> First of all you can forget about C/C++. Everything in this languages assumes free access to the system.
C/C++ works fine. It essentially acts like a bare metal embedded device, but without access to hardware registers. You cant even print to console by default.
This does means most of the C standard library won't work, but C itself doesn't care. There are no system calls either, only whitelisted functions calls statically provided to the WASM code. Again C/C++ don't care, but it means you can only use code that uses limited subset of the standard library.
The JVM's bytecode design makes it hard to translate C to it, whereas WASM is designed for languages like C with arbitrary pointer arithmetic. WASM just turns point access into memory offsets, while the JVM or CLR assume a Java like language.
> I don't find any such feature mentioned in the Wasmer docs. It seems completely without any sandbox!
Browsers have been shipping WASM VMs for years now without disaster, so apparently they do know whats required for sandboxing. If you can prove otherwise and break out of WASM you could make a lot of money from Google's security bounties or just selling it on the darknet. ;)
I'm sure theres been security flaws just like in any sandbox technology, but generally WASM appears successful. Its been adopted outside browsers by security conscious companies like cloud-flare and fastly to provide sandboxing of user code, etc.
> (To stress it once more: All VM languages are memory safe. That's not sandboxing. All the "sandboxed by default" claims are misleading, at least).
You're correct that limiting memory access is only part of what a sandbox requires. Memory safety is a crucial piece of sandboxing, though many VMs do provide that. However most VMs also provide mechanisms to escape the memory sandbox though so they're not good at being sandboxes.
The other crucial part for sandboxing is control flow. The VM must prevent code from being able to hijack control flow, or to otherwise generate code to escape the sandbox. The links you provided discuss how WASM does this currently:
> All control transfers—direct and indirect branches, as well as direct and indirect calls—are to known and type-checked destinations, so it's not possible to accidentally call into the middle of a function or branch outside of a function.
What most of the hype around WASM is actually about is the ability to provide this sandbox isolation after translating WASM bytecode to native binary code.
Most JVM VMs also do JIT'ing at runtime, but the JVM has some runtime features and assumptions that make statically compiling upfront harder. WASM was designed to enable ahead of time compiling from the outset. That is a key difference between JVM and WASM.
For example here's a paper from Stanford & UC folks for a static verification engine for checking that binary executables translated from WASM to maintain the sandboxing: https://cseweb.ucsd.edu//~dstefan/pubs/johnson:2021:veriwasm...
> One should never over promise on security! Java had to learn this the hard way over many years (as their sandbox had have holes in the past, and was also almost impossible to correctly configure).
To reiterate, WASM incorporated these details from the outset, to the point that providing useable WASM VMs outside of browsers years to come about.
If you're talking about WASI, you have a bit more of a point. WASI is the result of carefully adding back in things like FS access using capabilities and other techniques to keep it sandboxed. This is harder, and introduces more surface area to violate WASM's sandboxing. However WASI seems well thought out so far.
> > One should never over promise on security! Java had to learn this the hard way over many years (as their sandbox had have holes in the past, and was also almost impossible to correctly configure).
> To reiterate, WASM incorporated these details from the outset, to the point that providing useable WASM VMs outside of browsers years to come about.
Could it be that you just again confused "sandboxing" and memory safety?
The problem with the JVM sandbox (and most of the time other VM languages) isn't memory safety!
There have been such bugs here and there, sure. In the JS VMs, the WASM WMs (like pointed out in the above linked paper), and also the JVMs.
But those bugs are the usual implementation bugs.
Once again, this is not relevant to the questions here. Memory safety is not a "sandbox"!
> WASI is the result of carefully adding back in things like FS access using capabilities and other techniques to keep it sandboxed.
What "sandbox" are you talking about?
There is only one WASI implementation that offers a extremely simple FS access filter. (And Wasmer, which we're taking about here, does not even have that, as I see it).
Capability security? Where is this implemented?
One again: I don't talk about what people dreamed up! I'm asking for the status quo.
> This is harder, and introduces more surface area to violate WASM's sandboxing.
Yes, that's the point.
Having a cage that does not let anything through is easy. Just build massive walls without windows and doors. Nothing can get out. Nothing can get in…
But such a cage is almost useless.
So the interesting part starts when a thing in the cage needs to talk to the outside world!
"Solving" the "trivial" problem is indeed easy.
Now show me how you solve the real problem!
But to my knowledge there is nothing there. Nothing. (Besides promises and cool sounding plans for some distant future).
> However WASI seems well thought out so far.
Yes, "thought out". But not implemented!
BTW: They did not come up with anything new here.
Capability security is at least around 40 years old.
The point is: Nobody ever implemented this outside of academia.
We have just now the first steps in that direction.
But that are at best beta versions of tech form the future…
As it stands today: WASM does not have any meaningful sandbox. (Memory safety is not a sandbox! It's "just" a prerequisite to be able to implement a sandbox. But it's not one by itself, and a feature _every_ VM runtime provides).
Even containers will give you more sandboxing based on the (by now) rich features of Linux namespaces. (Still nobody considers this a serous sandbox on which you could bet your ass. That's why we run containers in VM; because that's the only—more or less—reliable sandbox we currently have; as our OSes and hardware still don't provide capability security features).
---
Don't get me wrong though.
I do think that the whole "linear memory" idea for memory safety is indeed a very good one.
It's so good, I think this should be implemented on the HW level! (Or at least in a first step on the OS level).
But "really safe memory cages" aren't sandboxes.
Without capability security on top this does not provide any meaningful improvement over what we have already since decades.
But capability security isn't something that you can just to piggyback after the fact. Everything, form the languages used and their libs, up through the OS and VM layers need to be explicitly build with this mechanism in mind. We're still light years away form having such infrastructure!
But what the WASM people present is some fantasy world where all this is already in place.
Given how aggressive those obvious lies are pushed I can't come to any other conclusion than that there is a lot of bad faith behind this campaigns. "Someone" tries to push by all means their VM tech into the market. Even they're leaking around 20 years behind the next competitor. This whole thing is a disgusting marketing war.
And to be honest I'm quite scared how effective this ultra aggressive marketing is even it's almost completely based on highly over promised stuff up to, in its extreme, blatant lies. I hope the person I'm talking to here isn't part of this marketing effort. And people reading this start to ask themself the "right questions" finally ;-).
> The FS sandboxing is actually part of WASI
AFAIK it's part of some WASI implementations, and not a mandatory requirement by WASI.
But maybe I'm wrong here.
Could you point to some authoritative documents that bakes your claim about WASI?
> […] where WASM is essentially just providing a way to run a function from JS with near native speed.
Could you explain how you get "near native speed" in a managed VM? No VM overhead on WASM? What did all the other VMs wrong for so many years that everywhere else there are significant overheads and slowdowns compared to native code?
Could you point to some benchmarks that bake your claim?
> C/C++ works fine. It essentially acts like a bare metal embedded device, but without access to hardware registers. You cant even print to console by default.
Could you explain how some random C/C++ program can run in an environment without the possibility to do basically anything?
What happens for example when I print to the console form such program?
> This does means most of the C standard library won't work, but C itself doesn't care.
How does a C program run without C library?
I was never talking about the C/C++ languages as such.
I said: You can forget to cross compile C/C++. Because I assume that almost no code C/C++ code out there will work in an environment without any possibly to do basically anything.
But maybe I'm very wrong here. Could you explain how this works?
> There are no system calls either, only whitelisted functions calls statically provided to the WASM code.
Ah nice.
And those calls are automatically sandboxes, yes?
How is the sandbox configured?
How does it prevent anything bad form happening?
This would require call filters, that inspect the parameters, and then decide what to do on every call, right?
If so, what's about the overhead of such a "call firewall"? How does it affect performance?
Where do I find the documentation for this sandbox?
> The JVM's bytecode design makes it hard to translate C to it, whereas WASM is designed for languages like C with arbitrary pointer arithmetic. WASM just turns point access into memory offsets, while the JVM or CLR assume a Java like language.
How is this relevant?
If WASM is modeled after the C languages requirements, why are people saying that it would be easily usable for other, high-level languages?
Wouldn't that mean that I need to write a VM that runs in a VM?
How would such a construct affect performance and resource usage?
What additional sandboxing could this bring to the table?
Please keep in mind here that the VM in the VM needs to talk to the outside world to fulfill it's std. lib contracts. How does this work?
> Browsers have been shipping WASM VMs for years now without disaster, so apparently they do know whats required for sandboxing.
But we're not talking about an JS VM embedded WASM VM.
We're talking about a standalone WASM VM outside of the JS VM.
How does sandboxing work there? How are the WASI calls sandboxed? (See also all the remarks above).
Where can I find the documentation for that?
> If you can prove otherwise and break out of WASM you could make a lot of money from Google's security bounties or just selling it on the darknet. ;)
Could it be that you just again confused "sandboxing" with memory safety? (Which is, once again, a property every "managed" VM runtime provides).
> Its been adopted outside browsers by security conscious companies like cloud-flare and fastly to provide sandboxing of user code, etc.
Oh, more sandboxing.
Could you point to some documentation how this sandboxing works on the technical level?
AFAIK they just run the usual containers in HW hypervisor VMs, where you can than place your WASM runtime…
So you get in the end sandboxing form the std. hardware based VM. (Because nobody trusts containers for security. And then anyway, in such scenario the workload inside the container is irrelevant).
> Memory safety is a crucial piece of sandboxing, though many VMs do provide that.
Could you point to any VM that does not?
> However most VMs also provide mechanisms to escape the memory sandbox though so they're not good at being sandboxes.
How is WASI different here?
What's the magic that WASI has, but nobody else?
Do you think a sandbox like the one that the JVM just throw away could prevent memory access outside the JVM? How does the provided escape mechanism work actually on the JVM? Is this part of the JVM? Or would it require some "unsafe" access through unofficial APIs which are not part of the platform?
Could you explain how this looks like in other popular VMs? I'm not familiar with such.
> The other crucial part for sandboxing is control flow. The VM must prevent code from being able to hijack control flow, or to otherwise generate code to escape the sandbox.
Could you explain why this does not work reliably on the JVM? (Even there is by standard byte code verification in place, of course.)
But please keep in mind that there is no user-level way to generate native code on the fly on the JVM. Only a JIT, which is actually not part of the platform, can do this. So how do I hijack control flow on the JVM (or other popular VMs)? Could you explain this (under the assumption that there are no bugs in the implementation of course, as this would render any VM protections on any platform likely useless obviously).
> What most of the hype around WASM is actually about is the ability to provide this sandbox isolation after translating WASM bytecode to native binary code.
Even in the face of implementation bugs in the "translator"?
How does this magic work?
Why do they still add "bumper spaces" around the WASM memory then? Should be strictly unnecessary given the magic property of WASM that the AoT compiler or JIT output is still safe, or not?
> Most JVM VMs also do JIT'ing at runtime, but the JVM has some runtime features and assumptions that make statically compiling upfront harder. WASM was designed to enable ahead of time compiling from the outset. That is a key difference between JVM and WASM.
How would this work with say Java on WASM?
What's the magic here again that makes it hard to AoT compile Java for the the JVM platform but it's easy to compile it AoT to WASM? What do I miss?
Could it be that this feature is only relevant in case the language you're compiling is anyway one of the few that are AoT compiled and not run inside a VM by default?
But than again, how is WASM the superior VM to run all kinds of languages like advertised (given almost all languages besides a few exceptions are VM languages)?
> For example here's a paper from Stanford & UC folks for a static verification engine for checking that binary executables translated from WASM to maintain the sandboxing: https://cseweb.ucsd.edu//~dstefan/pubs/johnson:2021:veriwasm...
Interesting.
Is this VeriWasm widely used in industry? Who's using it in production?
(One could also ask who verified the verifier implementation, but that's always the question with SW verification; usually you can "just trust" multiple layers of insights. Otherwise SW verification would be useless; which it's not imho!)
At least the introduction of the paper answers a few of the previous questions. Let me cite:
> WebAssembly (Wasm) is a platform-independent bytecode that offers both good performance and runtime isolation. To implement isolation, the compiler inserts safety checks when it compiles Wasm to native machine code. While this approach is cheap, it also requires trust in the compiler’s correctness—trust that the compiler has inserted each necessary check, correctly formed, in each proper place. Unfortunately, subtle bugs in the Wasm compiler can break—and have broken isolation guarantees.
I'm not further commenting on this part. I think the statements stand on their own.
There is nothing inherent in java bytecode that would make it unsafe, nor hard to AOT compile — runtime reflection is not part of the JVM spec itself, it is a separate API (akin to WASI) that provides this capability. So, a JVM interpreter can also do no harm without attaching the endpoints that can do harm obviously. Also, there used to be a project called gcj 20 years ago that managed to AOT compile java just fine, the only riddle here is the aforementioned reflection. Graal uses a closed-world assumption to solve it.
Your link is interesting though, will look into it.
Looks much like the byte-code verifier that is std. part of the JVM.
The foundations on which this is built look quite solid though.
Which ones?
AFAIK WSAM runs only "C-like" language properly.
Everything else is a major hack and slow as hell.
When it even exists of course. Because to my knowledge there aren't much languages that compile to WASM besides C/C++/Rust. Because WASM lacks features for VM languages (and that is the big majority of languages). Did something in this regard change lately?
And yeah, I guess we're able to run things in the browser with WASM. One could say "well why use it on a machine outside the browser", to which I reply the obvious thing: hell of a lot easier to just use one VM rather than two.
I think there are also social dynamics at play when it comes to _anything_ related to Oracle, which does poison the well. It's unfair to the GraalVM people's serious work, but it is what it is.
Really? I see marked as "production ready" (whatever this means in this case):
AssemblyScript
Brainfuck
C
C++
Go
Forth
Zig
Rust
COBOL
C#
F#
Lua
Clean
Lobster
TypeScript
Never
So the realistic options are: C/C++, Go, Zig, Rust, C#/F#, and Lua.Where C#/F# is slow as hell, with a gigantic overhead.
Lua is likely slow (don't know for sure).
The rest looks pretty much like "the C languages" to me.
> […] and you don't need special "GC support" in WASM to implement a GC in WebAssembly, at the cost […]
Oh, someone is prepared.
Sure, you can build such thing. One can also build a Web-Browser in Brainfuck; somehow (and than even run it in a WASM container).
The point is that that's extremely inefficient.
In the browser it does even make less sense as there is the JS VM with a pretty solid GC right next to the WASM runtime.
So compiling a VM language to WASM is already questionable in itself. But without proper low-level building blocks to implement managed language runtimes efficiently this can be hardly even called working. Just have a look how for example Blazor compares to native JS (which people consider slow and sluggish already):
https://krausest.github.io/js-framework-benchmark/2022/table...
We're talking about garbage collection though, this will always be inefficient, doesn't matter much on which side of the fence it is implemented. At best you can save some WASM download size by piggybacking on the Javascript engine's garbage collector (that's essentially what the WASM GC proposal is about).
No, that's just not true.
You can't implement GC in WASM currently in any sane way.
As already said more than once here: WASM is lacking needed features. (For example memory fence instructions).
Any GC build in WASM will be extremely slow and inefficient. It will be also a stop-the-world GC. Because you can't build anything else.
GC implemented in WASM is at the moment completely impracticable.
Sure, you "can" do it still. But that's like building a banking application in Brainfuck. You can do that. In theory. Maybe even someone did it "for real". All this does not matter. It's brainfuck.
And that's not only the GC.
VM runtimes, and JITs need some more features to be implemented efficiently.
WASM is also lacking those features (like computed go-to).
Bottom line is: It's impossible to implement a VM in the WASM VM even remotely acceptable.
This is also backed by data:
I've showed already the catastrophic performance of Blazor. (And this is something where millions of dollars went for years to make it even "work".)
Come on, it is a ridiculous claim. GCs can run completely concurrently with the actual code with barely any coordination between the runtime and the running code - they basically make allocation’s and deallocation’s costs asymptotically zero. You do not believe that manual allocations are free, right?
No, it isn’t. Memory management.
Also, so you want to write code with hardcoded sizes for everything or what? Yeah, I surely want programs that die on a string of length 35 because only 32 were allocated upfront.
Also, managed languages can have hot loops without any allocation going on, you know right?
Nothing beats clang's wasm output in that regard (e.g. both Emscripten's 'emcc' and Zig's 'zig cc' are drop-in replacements for a GCC-like toolchain which can produce WASM).
The difference is: The JVM is already proven in production since a very long time.
Not to mention runtime is anything but lightweight and easily embeddable.
> Not to mention runtime is anything but lightweight and easily embeddable
There are more JVM implementations than Wasm ones, I’m sure there are plenty small, embeddable one. But arguably the best would have been a single, performant JVM built into the browser instead of the JS engine, allowing for both scripted usage and this “sandboxed compile target” one. (Applets failed more due to politics, than anything)
This allows their unique custom use-case-specific code to be managed separately to Envoy, so it can be ported across upgrades etc. It also means that if there's a very particular feature you want that's unique to your business, and wouldn't make sense to contribute to the upstream OSS project, you can write a WASM module for it.
It's somewhat niche, because anything built in this way which is generally useful to many users, will probably just be made a native feature of the host platform. Conversely, anything that does something significantly complex and custom should probably live as it's own stand-alone microservice somewhere. There's still a lot of room for value between the two extremes though!
- Running code you don't fully trust on a server you do control
WASM comes with powerful sandboxing, and if you combine that with static linking you can pretty much drop Docker for your PaaS (and all the overhead/complexity/insecurity that comes with it). This is what Cloudflare Workers do
And why could/did those other virtual machines not evolve to fulfill the need that WebAssembly fulfills? Why is a new machine language and new virtual machine necessary?
All three were designed primarily as bytecode interpeters that would run as a layer between the OS and application, and were primarily designed to run stand-alone (i.e. desktop/server apps). Java was originally included in most web browsers, but the applet model just didn't get it done for users - and most Java software moved either be web applications (i.e. serving HTML) or desktop or mobile applications.
> Why is a new machine language and new virtual machine necessary?
WASM was designed to be embedable (and secure), streamable and is now ubiquitous as it is supported by all three major browsers, plus Node (and Deno) and many desktop web-app platforms (e.g. Electron). The embedable part is what makes it really different than JVM, CLR and BEAM - for example, you can include a WASM runtime in your application and call WASM code from a C or Rust app just like the browser does.
Had it been today, Google would have been able to push PNaCL no matter what.
> One of the exciting things in Visual Studio .NET is its language agnosticism. If a vendor has written a .NET-compliant language, you can use it in Visual Studio .NET. It'll work just as well as C# or C++ or Visual Basic. This isn't just a future feature-in-planning. There are already nearly two dozen languages being developed for Visual Studio .NET: Visual Basic, C#, C++, JScript, APL, Cobol, Eiffel, Fortran, Pascal, Perl, Python, RPG, Smalltalk, Oberon, Component Pascal, Haskell/Mondrian, Scheme, Mercury, Alice, and even the Java language.
-- February 2002 issue of MSDN Magazine
https://learn.microsoft.com/en-us/archive/msdn-magazine/2002...
As for the JVM, it is kind of ironic as well, that after bashing Java Application Servers, there are startups trying to replicate them using a mix of Docker containers, Kubernetes and WASM.
So they aren't that bad after all.
As part of that, it really doesn't do very much. Other more general purpose VMs first let you do things. This has implications for running untrusted code: the JVM has never _quite_ managed to lock things down, and has a model where we restrict code that would otherwise have access (via reflection) to a lot of things we don't want it to have access to.
WASM starts with a bounded set of "RAM" and the ability to define code that runs on a "CPU". There's no mechanism for the CPU to access anything outside of the data it's been explicitly allocated. That makes it more difficult to actually do anything, but also more difficult for malicious code to do anything it shouldn't.
With much stricter invariants comes the ability to statically validate the invariants, too. Which is where projects like Mozilla's use of WASM as an intermediate format that's then converted to C are really interesting: correctly written C will maintain these invariants too, but we can't validate them directly. We can validate the invariants in WASM then maintain them by construction as we convert to C and onwards to native code.
Outside the browser as the other comments say it's about sandboxing primarily, and the feeling that it's not too dependent on a single vendor. Of course that means not much useful code runs inside WASM. The hard bit about sandboxing is not actually doing it, so much as allowing a usefully flexible set of permissions and features for sandboxed code.
Interestingly, Graal is also developing a sandbox. And with native-image you can compile the language implementations down to native code. So you could soon (even today actually but it's not really advertised) load a sandboxing JS or Python or Ruby or indeed WASM implementation from a shared library using a simple C API. Again though the hard part is actually that "real" code tends to have extensive OS dependencies. The JS ecosystem finds wide usage partly because so many modules are written for the browser which allows very little, whereas in the Python/Java/etc ecosystems modules frequently will assume things like filesystem access.
> How to implement a safe<<R>> sandbox.
Putting ads in the low level runtime? :-))))
While wasmer seems to support more source languages, it requires running the executable under a WASM virtual machine. Are there other important differences?
> How is this approach different? ape is aiming to create one standalone binary that works everywhere (same chipset, x86 as lingua franca). On the other hand, Wasmer aims to have one standalone lingua franca (Wasm), that can target multiple OSes (macOS, Linux, Windows), chipsets (x86, ARM, RISC-V) and programming languages (Python, Rust, Go…).
> On one hand, both ape and Wasmer rely on a “universal binary interface” to interact universally with the Operating System: Cosmopolitan (as a universal libc POSIX interface) in the case of ape, and WASI in the case of Wasmer.
> On the other hand, since Wasmer relies on WASI it can also offer a full-sandboxed execution when running the binary (this means that by default no files or sockets could be accessed or created by the binary unless explicitly allowed, for example).
WebAssembly as a Universal Binary Format (Part II: WAPM) - Portable Executables - https://wasmer.io/posts/wasm-as-universal-binary-format-part...
I have a piece of library written in rust that i need to run on multiple different hosting environment due to business reasons, like java/js. They will all call this library to validate part of the logic at the same time do something else
Could wasmer help in this case for me to write once and have consistent behavior everywhere ?
For any language with decent cross compiling capability, is there a use case for `create-exe`? Eg i use Rust these days.. and i wonder if there's any use case for me to cross compile via wasmer instead of natively. My project(s) do work on WASM as a target (for browser reasons), maybe it would be easier to setup cross compiling via wasmer and not manage the release pipelines i have?
Though for some of my performance critical applications i may not want to bother with it. Simply because i'd suspect wasmer might not have the same platform specific optimizations that natively compiling would give me.
However, it seems they're making far more progress than wasmtime, so taking the bad with the good I guess.
Wasmer seems pretty cool, and may in fact be a future for micro-services.
This is based on what wasmer used to provide for wasi in the browser before they did their major rewrite in rust mentioned above. I personally find the JavaScript version more useful for my projects so I revived their old project and am maintaining it.
Nothings exploded so far: https://github.com/DustinBrett/daedalOS/commit/eb958836f1f5e...
$ wasmer create-exe --target x86_64-windows-gnu qjs.wasm -o ./js.exe && llvm-objdump -p ./js.exe | grep DLL
DLL Name: KERNEL32.dll
DLL Name: msvcrt.dll
DLL Name: WS2_32.dll
DLL Name: ADVAPI32.dll
DLL Name: USERENV.dll
DLL Name: bcrypt.dll[1]: https://medium.com/wasmer/wasmer-io-devices-announcement-6f2...
Link to example for this? Tried Wasmer about a year ago and had too much trouble passing multiple non-int args with a Rust host (so no JS bindgen)
[1]: https://github.com/wasmerio/wasmer/blob/master/tests/compile...