| You’re missing the point. You’re right there are unlikely to be bugs in vec, but there are also unlikely to be bugs in std::vector or WTF::Vector both of which error out on OoB (chrome/v8 uses hardened libc++). I was using `vec` as an example of runtime code that is fundamentally implemented in unsafe code. The errors that are being discussed are errors in the runtime - eg the unsafe{} blocks of rust. It’s very difficult to write code in v8/blink (or JSC/webkit) that interacts with the relevant JS runtime in ways that make the code unsafe - just as you cannot normally interact with `vec` in a way that causes a memory safety error - however the runtime’s implementation of the safe interface is still has to eventually perform unsafe operations. The bugs that you see in V8, JSC, etc are almost invariably in code that would necessarily be unsafe region in rust that would not be preventable in rust. Another example: `Arc`, `Rc`, and `Box` etc all allocate memory, and all your rust code can be built on those, and be safe (assuming no bugs in the refcounting, no compiler lifetime errors, etc), but the allocator beneath them still has to do everything correctly and the operations it performs are largely unsafe. There’s nothing rust can do to prevent a logic error from returning overlapping pointers. You can create lots of abstractions to make it harder to screw up, but you are the runtime at this point so the code that is requiring safety rules is also the thing specifying those rules. Eg if the erroneous state/logic that leads to an incorrect allocation is the same state/logic you are testing against to ensure you aren’t making an erroneous allocation. You can see how that impacts the safety profile of the code. When JSC or V8 have a use after free vulnerability it’s almost always a runtime error because the overwhelming majority of allocations made by both engines are via their own GCs, and so definitionally should be sound. But if there’s a bug in the runtime (a missing barrier, or a scanning error in JSC), then objects can be erroneously collected and that’s how a UaF happens. There’s nothing rust or any safe language can do to make those errors impossible or unexploitable. All the runtime can do is structure the code to make errors as hard as possible, in rust that means minimizing the amount of time in unsafe{}, and add mitigations such that any error that does happen is hard to exploit. When V8 and JSC have buffer overflows it’s because the metadata for an object says “there is this much memory available” but that is incorrect. Again rust cannot protect against this: you’re in the position of a `vec` with incorrect bounds information. And that goes on for all the types of bug class. The vast majority of the security benefits rust offers for a language and vm runtime are available - and used - in c++. The bugs are in the code that would necessarily be unsafe{}. Now in blink/webkit the moment you get beyond the relevant JS runtime you run straight into the standard C++ nightmare that rust, swift, JS, C#,… prevent so that’s another thing altogether. |
> This code makes the (reasonable) assumption that the number of properties stored directly in a JSObject must be less than the total number of properties of that object. However, assuming these numbers are simply stored as integers somewhere in the JSObject, an attacker could corrupt one of them to break this invariant. Subsequently, the access into the (out-of-sandbox) std::vector would go out of bounds. Adding an explicit bounds check, for example with an SBXCHECK, would fix this.
> *Encouragingly, nearly all "sandbox violations" discovered so far are like this*
Emphasis mine.
This sandbox is about injecting an indirection layer to protect against those JIT issues (which Rust doesn't help with) from being used to escape the isolate's memory. What that means is that JIT issue has to be combined with a sandbox escape to have the same exploit as just the JIT without the sandbox.
Thus, sandbox escapes are a real concern & a critical part of the security model. Those happen because of a memory safety issue in the C++ code, not because of the JIT. That's 100% by design because if the JIT bypassed the sandbox the sandbox wouldn't do anything.
A Rust sandbox written with `#![forbid(unsafe_code)]` wouldn't have these issues. It might still because even safe Rust isn't 100% guaranteed to be sound due to compiler bugs, but now you're having to pair a JIT issue with a compiled Rust memory safety issue which is much much harder. It's going to be at least an order of magnitude more reliable than C++ even with a hardened libc++. That being said, I don't believe the sandbox alone would be enough. I believe `JSObject::GetPropertyNames` is in the runtime & that again isn't directly invoked by JIT nor is it code that requires unsafe.