Hacker News new | past | comments | ask | show | jobs | submit login

> Can you provide an example of a dangling reference of any type (not just a UAF) being exploitable for RCE in a managed language like Java, Rust, or Go?

The point is that it doesn't matter what language is hosting the JIT. You can write this same bug in a program with a JIT hosted on the JVM, in a Rust program, or in a Go program. The code generated by the JIT is the equivalent of C FFI or an unsafe block, which completely ignores your "managed" language. V8 calls directly into and out of the JIT heap with a couple stubs a handful of instructions long, code in the JIT heap is whatever you generated, and can do whatever you told it to.

OK, but this bug isn't in jitcode.

I never said it was. I said it implicated JIT'd code and the complex GC subsystem. The context is a JavaScript ArrayBuffer, the very type of object that JIT engines are built to optimize access to, and thus it's reasonable to infer that there may be some sort of cross-runtime scoping aspect at play. Such code by definition not only bypasses language protections, most relevant to this case it implicates interfaces that, in the parlance of Rust, could only ever be implemented using unsafe{} blocks. Without knowing more we can't meaningfully perform root cause analysis.

Imagine passing a pointer to the backing store for Rust or Go arrays across an interface boundary. Imagine a JavaScript implementation also written in either of those languages, but where the entry point interfaces prevent the language (caller or callee) from tracking and ensuring lifetime invariants across the boundary (certainly not statically, nor dynamically because we're not using a unified abstract VM like the JVM or CLR). Correct memory management necessarily relies on the programmer explicitly and manually synchronizing liveness between those distinct environments. If they get it wrong it's not Rust or Go's fault, nor can you squarely lay blame on either side of the interface boundary; it's the programmer's fault and/or poor interface design; and the likelihood of such a bug is equally likely in Rust, Go, or C++.

JIT also comes into play because even if the entirety of Chrome or Mozilla were nominally implemented in Rust or Go, the compilers and runtimes of either language could not ensure correctness of the generated JIT'd code nor track dependencies across native Rust/Go code and the generated JIT'd code--particularly for JavaScript code where the norm is object lifetimes escaping function scope. JIT'd native code effectively, if not formally, results in two distinct, disjoint runtime environments. Correctness, again, would be predicated on correct use of interfaces that might look suspiciously like malloc/free. The better interfaces would expose and emphasize the semantics of anchoring and referencing binding directly, but such interfaces are difficult to design and implement--after all, if they were then the argument that safe C++ is too difficult in practice wouldn't have such weight.

There are entirely interpreted JavaScript engines. Rhino is a obvious example for Java. Duktape is a nice, embeddable interpreter written in C. Theoretically it could be rewritten in Rust, but that wouldn't make it any more likely to displace implementations like V8. And that's my point. In reality the fundamental problem isn't that we're not using a Rust-written Duktape (it's manifestly not a realistic expectation, not in the domain of JavaScript engines), it's that we don't invest enough attention in integration across inevitable language boundaries.

Yes, there has to be some unsafe glue code somewhere. So what? You write it once and wrap it in a safe interface (there are at least three relevant options in the crate ecosystem that I mentioned). That way, programmers who hack on FileBuffer don't have to worry about introducing zero-days like this.

This is not feasible in C++, because the language isn't safe to begin with.

JIT isnt unsafe glue. The very core concept of JIT breaks all compiler guarantees at runtime.

To be clear, regarding my rant about WebAssembly, it would be nice to see a WASM specification that permitted, for example, pluggable WebAssembly engines. Though performance may limit it's popularity, I'd like the choice to use an engine written entirely in a language like Rust or ATS. Many people here would use it, and it would add a useful competitive dimension that emphasizes security. Also, as I previously mentioned, such an interface could limit the risk of introducing and the scope of dangerous cross-subsystem dependencies invisible to host languages and which result in memory issues.

But that can never happen if the WASM specification insists on semantics that all but require tight integration with the browsers' JavaScript engine and GC.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact