A major source of vulnerabilities is (still) the Javascript engine and that's (still) written in C++.
Even worse, as far as I know, Mozilla has no plans to rewrite even parts of Spidermonkey in Rust.
For some recent examples:
A major source of vulnerabilities is (still) the Javascript engine and that's (still) written in C++.
Even worse, as far as I know, Mozilla has no plans to rewrite even parts of Spidermonkey in Rust.
For some recent examples:
There will probably always be C++ code in Gecko, but I firmly believe that writing more components in Rust instead of C++ will (in general) improve security and developer productivity.
It still amazes me that we're actually shipping a browser with a CSS engine (and soon graphics engine!) written in Rust. Even more amazing is that these components are mostly shared with an entirely different browser engine.
One class of vulnerabilities in JS engines is use-after-move. A raw pointer is extracted, an allocating function is called (triggering a GC), then the raw pointer is used, pointing into nowhere. It's awkward to express in Rust that a function may modify state inaccessible from its parameters.
A second class of vulnerabilities is type-confusion. A value is resolved to (a pointer to) some concrete type, but some later code mutates the value. Now the concrete type is wrong. Again this possibility is awkward to express in Rust.
The problem is complicated by the NaN-boxing and JIT aspects of JS engines, which interfere with Rust's tree-ownership dreams.
People smarter and way better at Rust than myself are working on it; I'm excited by the prospect of novel solutions that can defeat entire classes of problems.
I'm excited to see a practical programming language that implements full dependent typing; languages like Idris are actually really good at dealing with precisely the kinds of situations you mention.
This feels like a hopeless problem; can any of Rust's powers be brought to bear here? Could Idris?
fn arrayLength(x: JSArray*) -> n: uint (requires nothing) (ensures length of x = n, changes nothing)
fn callToJson(x: JSValue*) -> JSValue* (requires nothing) (ensures nothing)
fn arrayAccess(x: JSArray*, m: uint) -> JSValue* (requires length of x > m) (changes nothing)
(NB: F* syntax doesn't look much like this, but I'm guessing this will be readable to more people on HN)The stuff in parentheses after each function type are the preconditions and post-conditions respectively. So if you do something like:
let x = arrayLength(someArray)
for i in range(x) {
let element = arrayAccess(x-1)
}
It will typecheck just fine. But if you add the call to toJSON: let x = arrayLength(someArray)
for i in range(x) {
let element = arrayAccess(x-1)
let transformed = callToJson(element)
// ERROR: (requires length of x > m) not satisfied for all runs of loop body
}
Since callToJson cannot ensure any property of the heap after it runs. In this way you can elide range checks when needed for performance without worrying that you've sacrificed safety.Covering all the cases a JS engine would need without adding 10 million lines of proofs to the size of SpiderMonkey is still an open problem, but this general approach (known as Hoare Logic[1]) is very enticing, and the type systems that languages like Idris and F* have are definitely the closest to realizing it in more places. There are real software engineering efforts using descendants of Hoare logic like TLA+ (notably Amazon IIRC), but it's rare to see it even in huge projects like browsers.
It's also critical to note that the heap concept of F* is not a totally fixed part of the language; most of the specification of how heaps work are actually in the standard library. That level of flexibility is what I think makes these languages likely to become capable of tackling these problems: something like a JS engine or any optimizing compiler is exactly the kind of place where being able to come up with your own type-level verification model is worth the effort.
Here's a substantial part being rewritten in rust by Mozilla: https://github.com/CraneStation/cranelift/blob/master/spider...
I stand corrected though, every little bit helps. Here's hope they'll start using Rust in more places where it counts.
https://bugzilla.mozilla.org/show_bug.cgi?id=1493900
https://bugzilla.mozilla.org/show_bug.cgi?id=1493903
To be fair I'm not actually sure rust would fix either of the CVEs I linked. Both being about problems in the generated code (as I understand them from a glance), which is something inherently unsafe to do.
Edit: I realized you might be picking out the word "ARM" on that page. I know Crainlift also works on x86, and I assume it's intended to replace IonMonkey everywhere, not just on ARM chips.
I mean, if you just want to compile the code, sure.
Executing arbitrary machine code not generated by the rust compiler (i.e. by the JIT compiler you wrote in rust) is basically the definition of unsafe though...