Live data from Hacker News

PartialExecuter: Reducing WebAssembly size by exploring all executions in LLVM

leaningtech.com

51–60 of 111 posts

Re: PartialExecuter: Reducing WebAssembly size by exploring all executions in LLVM

#51

Earlier quoted context omitted.

This sounds like ActiveX. Security issues related to ActiveX are solved or not? Because if they are not, then it's just a reskin of ActiveX and malware authors gonna have a field day.

There is a very big difference: ActiveX was native code that was literally running on your system with full access to system calls. CheerpX is a Virtual Machine environment, it JIT compiles Wasm code from x86 binaries and it is fully sandboxed by the browser. It _cannot_ access your system even if it tried.

> It _cannot_ access your system even if it tried.

That’s the intent, at least. I’m sure we’ll get to see exploits that manage to do exactly this.

Re: PartialExecuter: Reducing WebAssembly size by exploring all executions in LLVM

#52
post #40
post #36

Earlier quoted context omitted.

Right, you can corrupt memory and thereby alter behavior, but that memory is a managed array. You can't corrupt anything outside of the application's own memory. As you say, you can change behavior, and thereby do whatever you want with whatever the wasm application is allowed to access. Which is a very limited set of things. Likening it to Java applets or Flash is deceptive -- yes, you can still hack them and exploi…

Imagine a WASM module used to control security authentication in the browser, or controlling IoT devices in a factory, now that it is fashionable to run WASM outside of the browser.

Right, I agree that wasm being used to control nuclear launches is not fundamentally better than native sandboxed C++ code in terms of preventing unwanted nuclear launches.

But wasm being used to control the brightness pattern of a blinky light on the console of the machine that controls nuclear launches? That is fundamentally safer than native sandboxed C++ code being used to control the blinky light.

I'm guessing we don't actually disagree on anything here -- I also feel like people are making unwarranted assumptions that wasm gives you more safety than it actually does. (It reminds me of another incorrect assumption that seems to get made a lot, that running unsafe code in a VM means you don't need to worry that it'll escape to the host or other VMs on that host.)

Re: PartialExecuter: Reducing WebAssembly size by exploring all executions in LLVM

#53
Thanks for sharing, we ended up designing something very similar in Scala Native [1]. The use case we had was to explore all possible code paths was to reduce the overhead of virtual call dispatch (since very often virtual calls have very few targets in practice), which is extremely dominant and prohibitive in JVM languages unless optimized away. I hope to see your work upstream in LLVM.

[1]: https://scala-native.readthedocs.io/en/latest/blog/interflow...

Re: PartialExecuter: Reducing WebAssembly size by exploring all executions in LLVM

#54

This is sweet! This is actually a very similar approach to how I deobfuscate Python bytecode: https://github.com/landaire/unfuck/blob/bfa164b4e261deffeb37... My code is pretty messy, but I take the same exact approach of taking known function parameters, interpreting the instructions, and removing any condition and the instructions which built its arguments if it evaluates to a constant value. Even called it partial…

Congrats, later will check & take inspiration!

Re: PartialExecuter: Reducing WebAssembly size by exploring all executions in LLVM

#55
post #28

Earlier quoted context omitted.

There is a very big difference: ActiveX was native code that was literally running on your system with full access to system calls. CheerpX is a Virtual Machine environment, it JIT compiles Wasm code from x86 binaries and it is fully sandboxed by the browser. It _cannot_ access your system even if it tried.

It can still be exploited the Applets/Flash way, by forcing the internal memory to become corrupted and with it change its behaviour.

Wasm has the same security risk as executing JavaScript in your browser, except with less risk of XSS type security issues because wasm modules are better encapsulated.

Re: PartialExecuter: Reducing WebAssembly size by exploring all executions in LLVM

#56
post #17
post #9

This company has an x86-to-WASM compiler that lets you execute arbitrary binaries in the browser. Also a JVM to WASM transpiler. There's a fantastic Meetup presentation given by one of them where they show running a C++ multiplayer game with both client AND server running in a browser, using WebRTC as a networking polyfill. Really mindblowing: https://youtu.be/7JUs4c99-mo?t=167

At what point does the browser become an "os", what's next? Chrome hypervisor?

I'd be much more willing to execute some binary in my browser than directly on my OS. Sure, you could do a VM or so, but a browser tab is spun up much more quickly.

The absence of friction of just executing something quickly, and being able to share it with a single text string, is what makes this appealing to people, I reckon. I dunno why people seemingly get offended by this.

Re: PartialExecuter: Reducing WebAssembly size by exploring all executions in LLVM

#57
post #51

Earlier quoted context omitted.

There is a very big difference: ActiveX was native code that was literally running on your system with full access to system calls. CheerpX is a Virtual Machine environment, it JIT compiles Wasm code from x86 binaries and it is fully sandboxed by the browser. It _cannot_ access your system even if it tried.

> It _cannot_ access your system even if it tried. That’s the intent, at least. I’m sure we’ll get to see exploits that manage to do exactly this.

Perhaps, but if so, that would be a bug in the browser’s WebAssembly implementation, not CheerpX.

Re: PartialExecuter: Reducing WebAssembly size by exploring all executions in LLVM

#58
post #4

Are the these new techniques only applicable to WebAssembly? If so, why?

GCC and Clang aren't super aggressive with DCE (dead code elimination) because most of the time the complex cases for DCE have essentially no impact on run time performance, and may be expensive to implement (i.e. significantly increase compile times).

For example, suppose you have a library that is configured with some options struct that contains a bunch of flags/settings. The behavior of the library changes based on these flags. The compiler will see a bunch of branches like "if (opts.foo) { ... }" and will generate code for all of these branches of. Now let's say you statically compile this library, and in practice in your code you only ever has one set of options enabled. In principle the compiler could figure out which branches can be eliminated based on the single instantiation of the opts struct in your code, and eliminate dead branches. But in practice neither Clang nor GCC will actually do this kind of DCE even at -O3 because it's simply not worth it. By the way, this kind of example is exactly the kind of DCE that the blog post is talking about and could be removed by the new DCE pass implemented by the author.

How big of an impact would this kind of DCE make on performance? Well the compiled binary size will be a bit smaller, which is kind of nice. But in practice this will have almost no impact on performance. Loading and mapping an ELF file is practically instantaneous even on huge executables. The branch predictor will predict all of the options branches that are hit repeatedly at close to 100%. Eliminating the branch entirely is in theory better than having a branch with a 100% hit rate, but hard to demonstrate in real world benchmarks for all but the most critical code paths. If there are large pieces of code in the executable that are unused they'll be mapped but won't even be page faulted during program execution. There are some kind of hand wavy arguments you can make about the extra code wasting space in the icache but again it would probably be difficult to actually demonstrate the impact even in microbenchmarks.

This isn't to say that there are no benefits to more expensive DCE passes. But they're generally extremely meager, so it's not worth increasing compile times for most applications. Wasm is an exception because compiled assets need to be transferred over the network and apparently it takes longer to load wasm code than it does to map an ELF executable. It's also worth noting that Clang and GCC do a lot of other types of simpler DCE, and these simpler DCE passes can be critical for performance, so I'm not trying to suggest that DCE entirely is worthless; just that the type of DCE presented here is less useful for traditional compilation.

Re: PartialExecuter: Reducing WebAssembly size by exploring all executions in LLVM

#59
> We have named this optimization 'PartialExecuter', the key idea behind it being taking advantage of known function parameters to find inner code blocks that cannot ever be possibly executed.

I'm wondering, what exactly are the differences of this approach from "classical" partial evaluation? This seems to be a special case of it, unless I missed something.

Re: PartialExecuter: Reducing WebAssembly size by exploring all executions in LLVM

#60
post #4

Are the these new techniques only applicable to WebAssembly? If so, why?

At least, I hope these could be applied to other VMs like the JVM. I don't see any reason why it can't be done, but I'm not an expert at all.

From my understanding, the main issue is mostly that it is very complex / risky to do these optimizations, and the reward is deemed low for the JVM.

The main JVM target I can think about where it could probably be profitable is the Android subsystem, but why would you care to reduce OS / Apps size when the fact that phones get bloated is very good for your business since you also sell phones, so it's quite useful to push the user to renew its phone on a regular basis.

Post reply on HN