News for hackers. Stuff that matters.
Re:Serious Chrome zero-day by wahern on Wednesday March 06, 2019 @08:50PM (#19324915)
Without knowing more there's zero reason to blame C++. This looks like it implicates (a) a questionable but quite intentional performance optimization and (b) possibly a V8 GC race or otherwise an issue with reference consistency between the C++ code and the JIT'd JavaScript runtime. Both of those issues would exist regardless of the language chosen--D, Erlang, Java, Python, Rust, w'ever.

Remove V8's JIT and GC and then one can have a meaningful discussion about memory safe languages. But remove those and the vast majority of Chrome bugs would also disappear. Those are the places of highest complexity while also being the areas which no language offers any meaningful assistance.

And this is why I think it's crazy that the WebAssembly folks are dead set on a specification that presumes and requires tight, direct object bindings between the host and the WebAssembly VM, particularly wrt JavaScript GC integration, as opposed to using indirect references with a clear contract that employ proxy objects for anchoring--in effect a sort of runtime sandboxing which falls short of IPC but which substantially circumscribes system complexity (e.g. invisible data dependencies) and substantially preserves the ability for memory-safe host languages (compilers and runtimes) to meaningfully ensure their invariants.

What we need more than yet another memory-safe language is the motivation and experience in multi-language integration. What we're getting are another generation of programmers recapitulating many unforced errors. Memory-safe languages aren't new. Nor are memory-safe and ergonomic languages. Nor is, for that matter, the thinking that one can throw a single language at a complex problem despite the entire history of computer science being an unending parade of new languages and optimization models with poor integration stories. Bare C FFI is only the most minimal and easiest requirement to get correct when it comes to integration. There's so much more to the problem.

Re:Serious Chrome zero-day by titzer on Thursday March 07, 2019 @06:44AM (#19327277)
> Remove V8's JIT and GC and then one can have a meaningful discussion about memory safe languages. But remove those and the vast majority of Chrome bugs would also disappear. Those are the places of highest complexity while also being the areas which no language offers any meaningful assistance.

No, just no. The data just does not back this up. The vast majority of Chrome bugs are not due to the V8 JIT or GC. Full stop. There are JIT bugs, and there are GC bugs. Some are horrible, exploitable. But on balance they are not the majority, and they often take a lot of expertise to find and exploit. Many, many critical bugs are due to array buffers and lifetime management issues of their backing stores. E.g. just tricking one code path to get the length of an array buffer wrong, and suddenly you've got write access to all of memory. (E.g. I recall a bug we had where a user program could install a JS function as a getter for the 'byteLength' property on an array buffer. One codepath in V8 trusted the result of calling this getter rather than an internal lookup, and boom). But array buffers, JIT bugs, and GC bugs aside, there are just a crapton of bugs that are directly due to manual memory management in C++ and all the other pitfalls of C++. We'd be on much better footing to get rid of C++ altogether, as it is by far the most common source of bugs in Chrome. This is the reason for Oilpan/unified heap. Humans suck at managing memory. Let machines do it, IMO.

> And this is why I think it's crazy that the WebAssembly folks are dead set on a specification that presumes and requires tight, direct object bindings between the host and the WebAssembly VM

Well feel free to make a proposal. (btw, running out-of-process was one of the selling points of NaCl. It did not work well with web platform API integration. A long, complicated story. The NaCl folks work on Wasm these days).

Re:Serious Chrome zero-day by blub on Thursday March 07, 2019 @11:30AM (#19329369)
Instead of "getting rid of C++" in a project written almost exclusively in C++, it would seem more sensible for Google to just wait for Firefox to be completely rewritten in Rust in the next ~10 years and if it's really that much better, fork it, add some googley stuff on top like user-tracking and mandatory log-in and then release it as the new Chrome.
Re:Serious Chrome zero-day by stouset on Monday March 11, 2019 @07:05PM (#19363757)
Alternatively, since Rust natively interops with C and C++ pretty straightforwardly, it should be possible to write new components in something like Rust and opportunistically rewrite old components on an as-needed basis.
Re:Serious Chrome zero-day by pcwalton on Wednesday March 06, 2019 @09:32PM (#19325115)
> Both of those issues would exist regardless of the language chosen--D, Erlang, Java, Python, Rust, w'ever.

Not necessarily. If the language provides a way to ensure memory management of DOM objects is correct across language boundaries, it would provide an effective defense against these issues.

Safe memory management across a combination of managed and unmanaged code is a tough problem, and Rust (and perhaps Swift?) are the only languages I know of that have any attempts to solve it. It requires both language and library support. There are several competing solutions in the community: luster [1], shifgrethor [2], and josephine [3] come to mind. All of them allow this kind of code to be implemented safely.

[1]: https://github.com/kyren/luster

[2]: https://github.com/withoutboats/shifgrethor

[3]: https://github.com/asajeffrey/josephine

Re:Serious Chrome zero-day by mike_hearn on Thursday March 07, 2019 @05:44AM (#19327045)
GraalVM also has a way to do this - the 'unmanaged' C/C++ is upgraded to be automatically memory managed on the fly by compiling pointers into (gc'd reference, integer field offset) and then redirecting allocations to GCd heaps. There's more to it than that of course, but it means traditional C/C++ using new/delete and GCd languages can interop and coexist in the same process and heaps, and memory management errors in the unmanaged side are caught (cause VM termination).
Re:Serious Chrome zero-day by gpderetta on Friday March 08, 2019 @06:14AM (#19336602)
If you want GC there are available GCs for C++.
Re:Serious Chrome zero-day by pjmlp on Thursday March 07, 2019 @02:41AM (#19326248)
You are forgeting SOM and COM/UWP.

Actually something where Rust still fails short of being an alternative to Delphi/C++ on Windows, regarding tooling and productivity.

Looking forward to the HoloLens collaboration or Microsoft now pushing for Rust on their security guidelines will actually improve that experience.

Re:Serious Chrome zero-day by throwaway12iii on Thursday March 07, 2019 @02:35AM (#19326228)
From the rust Oxidization page (hip name):

- "Crossing the C++/Rust boundary can be difficult."

- "For components that are relatively standalone, with small and simple APIs."

- "This minimizes the C++/Rust boundary layer issues."

Not only does Rust not have a good JavaScript integration story, it doesn't have a good C++ integration story.

Most of Firefox is still (8 years later) not written in Rust.

Chrome with C++ has a waaaaay better safety record than Firefox. Guess what? The C++ in Chrome tries to ensure memory safety for JS.

The C++ Chrome tooling does a better job of memory safety as a whole system than Firefox.

Re:Serious Chrome zero-day by vthriller on Thursday March 07, 2019 @06:36AM (#19327244)
> Most of Firefox is still (8 years later) not written in Rust.

<nit>In part because 1.0 release of Rust popped up in 2015, not 2011.</nit>

Re:Serious Chrome zero-day by pcwalton on Thursday March 07, 2019 @10:37AM (#19328838)
None of this is responsive to my points.
Re:Serious Chrome zero-day by throwaway12iii on Thursday March 07, 2019 @12:05PM (#19329734)
Rust is bad at managing DOM memory in Firefox.
Re:Serious Chrome zero-day by krageon on Thursday March 07, 2019 @09:52AM (#19328446)
You make a lot of points about Rust and mention Firefox in your conclusion, right after saying Firefox is by and large not Rust. I think your logical argument would be better served by using clear language and a single subject. After you have those two things you can think about coming up with examples.
Re:Serious Chrome zero-day by staticassertion on Wednesday March 06, 2019 @09:11PM (#19325006)
> there's zero reason to blame C++

Seems like UAF in C++? So, yes, I feel comfortable blaming C++.

Anyways, I didn't mention memory safe languages in my post, and I'm not even suggesting that Google did anything wrong, or should change their posture in any way. They've been extremely successful.

Re:Serious Chrome zero-day by wahern on Wednesday March 06, 2019 @09:38PM (#19325152)
UAF by whom? If it's through a bare reference held in the JavaScript VM where operations don't access the C++ object as a C++ object or as some shared primitive object as in the JVM or CLR, then the error is in maintaining state consistency across distinct environments. Such bugs look exactly the same in every language, although the risk is compounded by (a) JIT'd environments and (b) asynchronous execution.

In the context of a bug involving JavaScript ArrayBuffers (where JIT compilers are designed to optimize away both FFI accessors and bounds checks) and asynchronous events I think it would be prudent to withhold judgment.

Re:Serious Chrome zero-day by tptacek on Wednesday March 06, 2019 @09:46PM (#19325185)
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?
Re:Serious Chrome zero-day by microcolonel on Wednesday March 06, 2019 @10:08PM (#19325250)
> 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.

Re:Serious Chrome zero-day by pcwalton on Wednesday March 06, 2019 @10:20PM (#19325289)
OK, but this bug isn't in jitcode.
Re:Serious Chrome zero-day by wahern on Wednesday March 06, 2019 @10:51PM (#19325392)
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.

Re:Serious Chrome zero-day by pcwalton on Wednesday March 06, 2019 @11:41PM (#19325545)
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.

Re:Serious Chrome zero-day by rocqua on Thursday March 07, 2019 @02:37AM (#19326236)
JIT isnt unsafe glue. The very core concept of JIT breaks all compiler guarantees at runtime.
Re:Serious Chrome zero-day by wahern on Wednesday March 06, 2019 @11:38PM (#19325533)
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.

Re:Serious Chrome zero-day by fooker on Thursday March 07, 2019 @05:37AM (#19327006)
Yes, sure.

You write to a file, save the file name or file descriptor. Then when you read it back later, maybe you forget to validate the contents. This can be exploited depending on what you were doing with the data.

Do you now want to restrict what you mean by a 'reference'? You'll see that once you keep restricting that enough you first lose the ability to write fast programs and eventually useful programs(evidence: various 'unsafe' modes in so called safe languages).

Re:Serious Chrome zero-day by titzer on Thursday March 07, 2019 @06:47AM (#19327289)
> where JIT compilers are designed to optimize away...bounds checks

V8 does not optimize away bounds checks on array buffers. For one thing, array buffers can be detached, so their length can suddenly drop to zero.

Re:Serious Chrome zero-day by wahern on Thursday March 07, 2019 @06:03PM (#19333520)
It does for native arrays, at least:

> This is the incorrect optimization we’re looking for. JavaScript array accesses are guarded by CheckBounds nodes, which ensure that the index falls within the array bounds. If the optimizer can determine statically that the index is always in-bounds, it can eliminate the CheckBounds node. Image tying the index to the result of Object.is: since the typing information is off, we could make the analyzer think the index is always in-bounds, while it can be out-of-bounds at runtime. The optimizer will incorrectly eliminate CheckBounds, giving us OOB access to a JS array, which we can use to construct more powerful exploitation primitives.

https://abiondo.me/2019/01/02/exploiting-math-expm1-v8/

See also

https://halbecaf.com/2017/05/24/exploiting-a-v8-oob-write/

Microsoft's Chakra engine:

https://www.thezdi.com/blog/2017/10/5/check-it-out-enforceme...

Hoisting a bounds check outside a loop is a common optimization, and I would be surprised if V8 doesn't do this for ArrayBuffers. But in any event my point is that the JIT compiler is in effect doing manual memory management outside the visibility of the host language, so for these types of bugs a memory-safe host language doesn't save you. And it can get this wrong and will get this wrong because these are extremely complex systems with high code churn.

Re:Serious Chrome zero-day by titzer on Sunday March 10, 2019 @04:45AM (#19351031)
JavaScript arrays and ArrayBuffers are totally separate animals.
Re:Serious Chrome zero-day by pjmlp on Thursday March 07, 2019 @02:37AM (#19326239)
Regular PC world has plenty of experience in multi-language integration.

SOM in OS/2, COM/UWP on Windows, JVM, .NET, ILM and TIMI on IBM mainframes.

Only UNIX world has been relatively poor in this regard, sticking with bare C FFI.