Chrome has probably invested > 1 billion dollars into their codebase at this point. Certainly >100million into security.
They sandbox their code aggressively. They build this project with security in mind from day 1 - it's been architected for it.
The Chrome security team(s) has a lot of power for a product security org.
They fuzz. They invent new fuzzers. They cluster their fuzzers.
They have a world class bounty program.
They have a world class research team for finding vulns.
They invent or otherwise aggressively adopt mitigation techniques.
But someone out there did it.
Their track record for security is something to really be proud of - this is the first public ITW exploit of its type that I am aware of. But users are getting owned because of, at the very least, a Use After Free vulnerability.
Let's just collectively admit it, finally - you can't write safe C++ in a codebase this complex.
edit: (From a post below)
To be clear, I'm not saying "Chrome should be rewritten in a memory safe language", I'm saying that Chrome is an excellent project to point to, say "Wow, no one does as much to secure a codebase as them", and to follow that up with "and they still got owned by UAF".
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.
> 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).
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.
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.
> 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.
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).
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.
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.
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.
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?
> 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.
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.
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.
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).
> 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.
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.
Linux is another good example how C doesn't cut it, even among top developers.
They have a very strict patch review process in place.
They have kernel static analysers.
The kernel has been adding security gates through the years.
Yet 68% of 2018 CVE's were caused by memory corruption bugs, with the others ones left out being UB, numeric conversions, and very tiny fraction remaining of the logic error kind that are bound to happen in any programming language. [1]
Just the other day we had a Linux 5.0 pre-release bug caused by a GCC "optimization".
Oracle went with hardware memory tagging for Solaris/SPARC, Apple is following along on iOS, Microsoft security advisory (as of Blue Hat conf) is C# + Rust + constrained C++ [2], Google is pushing for hardware memory tagging, Kernel Self Protection Project, constraining what the NDK is allowed to do and Fuchsia is getting more Rust/Go modules by the day.
What is clear is that hoping for the best and the mythical 10x developers that write perfect C and C++ code won't ever happen.
[1] Source, Google talk at Linux Kernel Summit 2018.
I still wonder what the plans for Fuchsia are. Is Google really thinking about just throwing out the millions of man-years which have been sunk into Linux?
They don't need to please everyone, just make their use case work.
Also porting the drivers to Fuschia should be relatively easy, thanks the Treble changes that kind of made their Android Linux kernel into a kind of hybrid-microkernel.
Android is already being ported to run on top of Fuchsia.
Google isn't the only one, the IoT space is getting crowed with BSD/MIT/Apache POSIX compatible OSes, including Zephyr from Linux Foundation, which is completly unrelated to Linux.
28 years ago no would would believe that Linux distributions would eventually kill commercial UNIX.
> 28 years ago no would would believe that Linux distributions would eventually kill commercial UNIX.
That's certainly a fair point.
I was thinking more along the lines of that, at least in the scenario of consumer usage of Linux, some really interesting features are finally gaining traction from various companies (3D accelerators for instance). Was just fearing that ditching existing work for the new shiny thing would send us back to square one.
And almost every operating system in the world is written in C by top developers who are in the know. If there was a better way, everyone would do it, but they don't.
Let's quit pretending that any software written in any other language would be more secure and have less bugs.
A monopoly is naturally self-sustaining. It's absurd to think there couldn't possibly be a "better way", that C is somehow perfect in its niche (that all-encompassing niche, that once covered anything and everything that wasn't grabbed by perl); But major experience in developing OS's is with C.. the knowledge, experience, tooling, etc depends on C, because C already has complete and total dominance in the area.
It's difficult to consider working on OS's in not-C, because C owns the market and ecosystem, and everything revolves around it.
But that's certainly a different reason than the absurd imagination that it's impossible to produce a language with stronger guarantees on bug-prone programming tasks (there are many languages that do, some with GC, some with stricter typing, some with static lifetime tracking, and so it goes on). That our CS theorists are so utterly incompetent that they couldn't manage to come up with even a single useful improvement to the divine language, 50 years after the great wizard Thompson etched its wisdom into a core dump
Let's quit pretending that (continued) market dominance correlates to (continued) quality.
If there is a safer, cheaper, faster language to use, someone would be using it. For another language to take C's place, it needs to be at least two of those--maybe all three and more. Market dominance, if there is such a thing in this area, has nothing to do with it.
Market dominance can be read as ecosystem dominance, and that reading obviously exists. More specifically, the C language could be completely worthless on its own, but made good enough to be usable through tooling (eg fuzzing, valgrind, etc). As it turns out, theres a lot more involved in writing an OS than just the language; and its all so conjoined at the hip, enough so that it makes it quite difficult to change just the language. But this is an argument that despite C’s flaws, its existence is on the whole preferrable to a total rewrite.
>If there is a safer, cheaper, faster language to use, someone would be using it
someone is using other languages. Urbit, redox, lisp machines, mirage are all not-c systems/OSs. But you aren’t talking about writing an OS, you’re talking about writing a popular OS. Of which there are basically three worth noting, all of which happen to have sprung up around a similar timeframe, coincidentally when C was at its most popular...
You seem to have confused the software industry for some kind of meritocracy... it is not. It follows trends harder than than the fashion industry. Look ...anywhere... for examples: OS, DB, language, game design and tooling, the AI winters, the .com crash, everything about the web, HN itself, etc. Hell, your own argument is just bandwagoning, with nothing about the technical merit (smarter people than I are using it, thus I should... is exactly how we end up in this state)
Let stop hand waving C security exploits caused by top developers, in spite of best practices.
C only got outside UNIX in the mid-90's.
Its ubiquity is an historical accident, by no means permanent, and thankfully some vendors are finally walking away from it, as proven by Microsoft security advisor for future Windows development best practices.
I'm pretty sure C was pretty well thought out and wasn't used by accident in any way. After almost 50 years of usage, I'm not sure we can say it's "by no means permanent" either.
C only got where it is thanks to Bell Labs not being allowed to sell it commercially, thus giving it away for a symbolic price to universities alongside source code.
Those university students went out to found startups that created the UNIX workstation market, like Sun.
Had Bell Labs been allowed to sell UNIX, C would have been a footnote in systems programming languages.
Instead gratis won and we got the JavaScript of systems programming.
EDIT: This is how well C was thought out.
"Oh, it was quite a while ago. I kind of stopped when C came out. That was a big blow. We were making so much good progress on optimizations and transformations. We were getting rid of just one nice problem after another. When C came out, at one of the SIGPLAN compiler conferences, there was a debate between Steve Johnson from Bell Labs, who was supporting C, and one of our people, Bill Harrison, who was working on a project that I had at that time supporting automatic optimization...The nubbin of the debate was Steve's defense of not having to build optimizers anymore because the programmer would take care of it. That it was really a programmer's issue.... Seibel: Do you think C is a reasonable language if they had restricted its use to operating-system kernels? Allen: Oh, yeah. That would have been fine. And, in fact, you need to have something like that, something where experts can really fine-tune without big bottlenecks because those are key problems to solve. By 1960, we had a long list of amazing languages: Lisp, APL, Fortran, COBOL, Algol 60. These are higher-level than C. We have seriously regressed, since C developed. C has destroyed our ability to advance the state of the art in automatic optimization, automatic parallelization, automatic mapping of a high-level language to the machine. This is one of the reasons compilers are ... basically not taught much anymore in the colleges and universities."
-- Fran Allen interview, Excerpted from: Peter Seibel. Coders at Work: Reflections on the Craft of Programming
Modern C is very different to K&R's C. Which itself was based other programming languages before it (like B - got to love their naming convention for programming languages!). But the history of C aside, it wasn't the only language that operating systems were built on. LISP, Pascal and obviously assembly / machine code too. In fact Pascal was a very popular systems language on home computing in the 80s and early 90s. If I recall correctly it used heavily by Microsoft and Apple too.
Don't get me wrong, I do like C. But it wasn't the run away success nor holds quite the monopoly you suggest it does.
Let's just collectively admit it, finally - you can't write safe C++ in a codebase this complex.
Do they distrust their own coders to the same degree they distrust the processes they sandbox? I suspect the answer to this is "no" but I would like to hear from someone who actually codes there.
I think the truth is more like this: You can write safe C++, just like you can keep a secret. It's just that the odds that you fail go up with the size of the team involved, and it does that by compounding. So by the time you get to the size of the Google Chrome team, the odds of failure are very, very close to 1.
> Do they distrust their own coders to the same degree they distrust the processes they sandbox? I suspect the answer to this is "no" but I would like to hear from someone who actually codes there.
Actually, the answer is yes. That's why the renderer process is sandboxed.
So what happened here? There's an in-the-wild exploit that's bypassing sandboxing - so there must be at least two bugs, or the sandbox isn't tight enough (which, for Chrome, would surprise the hell out of me).
"The second vulnerability was in Microsoft Windows. It is a local privilege escalation in the Windows win32k.sys kernel driver that can be used as a security sandbox escape."
I used to work on Chrome. There have been periodic sandbox escapes, and chained exploits that escape to userland are routinely performed at pwn2own. This is just notable because there is a live exploit in the wild.
I listed a subset of the things Chrome does to help mitigate the fact that C++ bugs will make it out. It's because they don't trust C++ that this is the case.
What is interesting is that, in the case of the first itw exploit, the root case appears to be memory safety. That despite the many millions invested, memory safety was still what an attacker went after and managed to leverage into an exploit against users.
I think it's a time that we should get rid of this notion of "perfectly safe code in the perfect world". It might be possible if the code doesn't change for million years, but that's not how the world works - things keep changing, the specs, the requirements and the users. Bugs are created every day. It's not about safety as a static property, but it is about the safety in an ever-changing world. As Bruce Schneier put it, it's a process. And yes, C++ might be bad for it, but that's only a part of the whole picture. We should look at the process rather then the code itself.
The OP’s entire point is that effectively no one has looked at the whole process in a more robust way than the Google Chrome team. They are literally at the vanguard of that issue, yet they got owned up by a well known code problem.
The real problem is that the web is now too complex to the point that it's impossible to safely implement it. And W3C keeps trying to add new features to it. At some point we have to stop and consider whether all this cruft is even necessary.
"Polyfills" are quite common in Web development, and are also proof that browsers do a whole bunch of unneeded stuff (if it were needed, there would be no way to polyfill it).
I actually think polyfill usage is backwards: the current approach allows code targetting new features to be made compatible with old browsers, by the site providing polyfills.
I think it's much better for new browsers to be leaner, simpler and more well-thought-out than their predecessors. Such browsers can provide polyfills to allow compatibility with code targetting old features that have been dropped.
In other words, browsers should be getting smaller (e.g. a canvas, audio stream, input method and language interpreter); more and more functionality should be offloaded into interpreted libraries (parsing, text rendering, DOM, event loops, layout, Javascript, etc.)
This _did_ successfully happen with MathML. It was on track to get native browser support, but they decided it the polyfill (mathjax) was good enough and wasn't worth native support for such a niche feature.
As a web developer, I much appreciate native features and avoid polyfills as much as possible.
Polyfills often are worse (slower, only provide parts of the functionality, ...) than the native implementation provided by newer browsers, so the browser implementation isn't strictly "unneeded".
If there's ever a project as large as Chrome written in a non-C++ language, I guarantee you it will have these bugs as well -- due to use of `unsafe`, or bugs in the compiler, or what have you.
How many remotely exploitable bugs in Java apps (that don't run arbitrary Java code†) do you see that arise from Java compiler bugs? I can't think of a single one.
†I explicitly say "not running arbitrary Java code" to emphasize the difference between this scenario and JS engine vulnerabilities. JS engine vulnerabilities are a problem because JS engines execute untrusted code, but I'm talking about compiler bugs in trusted code that can nevertheless be exploited remotely.
> How many remotely exploitable bugs in Java apps (that don't run arbitrary Java code†) do you see that arise from Java compiler bugs? I can't think of a single one.
Seems like an odd restriction to impose here. How many C++ exploitable bugs arose from a C++ compiler bug? I think the answer to that is also zero. Doesn't really seem like a useful thing to consider?
But in terms of Java runtime's security it's not particularly stellar. The entire category of "Java deserialization" is the never ending fountain of remotely exploitable security bugs in Java apps that don't run untrusted code.
> Seems like an odd restriction to impose here. How many C++ exploitable bugs arose from a C++ compiler bug? I think the answer to that is also zero. Doesn't really seem like a useful thing to consider?
Right, and that's why the fact that the Rust compiler has bugs is irrelevant. The language is meaningfully more memory-safe than C++.
> But in terms of Java runtime's security it's not particularly stellar. The entire category of "Java deserialization" is the never ending fountain of remotely exploitable security bugs in Java apps that don't run untrusted code.
Java deserialization RCEs, while pernicious, are nowhere near as common as use-after-free and related bugs in C++ code. Furthermore, you can effectively mitigate them by statically banning OutputObjectStream and whatnot. There's no such easy foolproof static mitigation available for C++ UAF.
> Java deserialization RCEs, while pernicious, are nowhere near as common as use-after-free and related bugs in C++ code.
Can you justify that? Actual exploits from Java deserialization RCEs are well known & published, but by contrast searching the CVE database reveals a rather small number for C++ or CPP. Use-after-free gets a large list, but the majority seem to be in C code not C++ code.
UAF are the most common, and the most commonly exploited kind of security bugs in Microsoft products for the last decade [1]. And Microsoft products are way more C++ than C.
I'm not sure how you'd even search for those, because deserialisation doesn't have an exact, common equivalent in C land. There are almost no cases of arbitrary/named types being constructed from arbitrary inputs at runtime. You have to take into account the really low prior probability for the counts to make sense.
It's a straightforward miscompilation. I'm not sure why they even classify it as a vulnerability.
From Microsoft, per the article: "The said vulnerability is about downloading and running untrusted code, which has always existed in all releases prior VS2017 Update 9 that supported lambdas. The scenario is not common coding practice and considering we've always had this in all our prior releases and have not seen any evidences of exploit it would not make sense to port the change as hotfix from 15.9 to prior VS releases."
In other words, it's never made into a product in an exploitable way. I'd just call this a miscompilation.
> If you’re still on the fence about deploying this update, we would consider it Important since it could allow for attacker-controlled code to execute at the level of the logged on user.
What does that even mean? I download some c++ code from the internet, compile it, run it, and... it runs as my user?
> Exploitation of the vulnerability requires that a user open a specially crafted file which was compiled with an affected version of Visual Studio. In an email attack scenario, an attacker could exploit the vulnerability by sending a specially crafted project, or resource file, to the user and convince the user to open the file.
So yeah sure looks like a basic code execution results in code execution. Surprised this even got a CVE.
I guess there is some conceivable exploit where you compile some hostile code written in a safe language to C++ with MSVC and then run it, and the attacker could exploit this bug somehow? But who does that?
How many remotely exploitable bugs in Java apps (that don't run arbitrary Java code†) do you see that arise from Java compiler bugs? I can't think of a single one.
If enough of a complex system is written in a language or run on a managed runtime that eliminates entire classes of exploits, then the developers will wind up implementing some optimizations and/or a way to write applications/plugins/extensions in C/C++. These mechanisms will open the doors to those exploits again.
(At least for now. Going forwards, I think we might be able to solve this one.)
Yeah, totally. I'm not saying they shouldn't use C++ (though I think they could probably save a ton of money if they did). I'm saying that they spend a lot of money on security, they do an incredible job, and stuff like this can still slip through, which I find really interesting.
In a general sense, I'd agree, but from the description in that article, it's interaction with native files or file dialogs. Even if you use Java, you're susceptible to this sort of bug, because your Java code calls into layer of C code to handle the native interaction.
Realistically, any browser is probably going to have a decent amount of unsafe code surrounding the native windowing, files, graphics, and so on.
Then I'll be that guy that tells you that including side channels after side channels (WebGL, WebUSB, FileStream), each with byzantine security features haphazardly tacked on, is the actual problem.
Completely agree. The refusal of us nerds to accept that our tools can be improved and replaced is a broken record that has been playing since the dawn of programming. It reminds me of how assembly programmers rejected high level languages; even with the glaring historical repetition, we are unable to recognise our loyalty to all languages is irrational.
It’s patently obvious C/C++ is just a bad choice for many tasks, particularly where security is so important. I’ve never heard someone who works with those languages agree.
However - if you’re reading this and feeling vindicated in your particular language choice - be prepared to accept that the language you favour right now is already or will soon be in the same position. That’s progress. Even if you love Haskell or Rust or Scala or Ocaml, if you think it’s anything but a stepping stone in language development then you’re just as wrong as those defending C/C++. As far as programming languages are concerned, we still don’t know what we’re doing.
If you have managed to be open minded about languages, then test yourself further by telling yourself that emacs/vim is a local optima and will be superseded by better programming tools, and you should be exploring IDEs and imagining what a world than doesn’t code in plain text could look like. Because typing coding in text form is almost certainly not the best way to write programs, any more than assembler was.
Is there an official explanation of the kind of bug? I cannot find it.
"Let's just collectively admit it, finally - you can't write safe C++ in a codebase this complex."
Pointing the finger and saying "see?" is a pretty low quality argument.
So, I guess we should wait for the first Rust or managed language remote exploit (or whatever) to say "admit it, finally - you can't write safe... programs?".
"Chrome has probably invested > 1 billion dollars into their codebase at this point. Certainly >100million into security."
Let's conservatively say Google pays 1,000 developers to work on Chrome, and on average those developers cost Google $300k each. That's $300 million a year just in payroll. Google has invested far more than a billion in Chrome by this point.
I'm amazed. Are there really, "conservatively," 1000 developers working on Chrome full-time, for years? That seems incredibly high to me, but maybe I just don't realize what it takes to build an app like Chrome.
As an estimate I think we can safely say it's not conservative. Especially if this is actually developers (ie straight up coders) and not also all of their supporting personnel.
Sure, but is your goal maximal safety no matter the cost, or are you trying to strike a balance with other factors?
If all you want is to keep users safe then it'd be easy - ban JavaScript wholesale. Bam, done, instantly made the web safer & faster. Don't even need to deal with the huge security can of worms that is WebGL, either.
But safety is rarely the exclusive factor in play, now is it? Things like memory usage efficiency & performance also play large roles here.
To be clear, I'm not saying "Chrome should be rewritten in a memory safe language", I'm saying that Chrome is an excellent project to point to, say "Wow, no one does as much to secure a codebase as them", and to follow that up with "and they still got owned".
But to what end? Pure-java apps get owned all the time, too. If you look over there you'd just give up on ever trying to transmit data, as the number of Java de-serialization exploits is nothing short of stunning.
The only semi-proven way to not get owned at this point is to never go online.
I'm not really interested in having a language shootout but I will say that I think you may be misunderstanding Java's history of serialization vulnerabilities.
You're right that it's a real footgun, the major issues that I'm aware of are in the native serializer, but yeah even the big libraries like Jackson have had issues.
I don't consider those on the same level as memory unsafety, personally, but it's not really a meaningful comparison because I'm not going to dig around for numbers and mitigation techniques.
I suggest that the most expedient (cheapest) language to migrate the existing code base to would be a memory safe subset of C++ [1]. In practice most of the safety benefit could be obtained from a just a partial migration. Specifically, just banning raw pointers/views/spans and non-bounds-checked arrays and vectors. From a quick glance at the code in the (quite small) patch diff, the code in question includes:
DOMArrayBuffer* result = DOMArrayBuffer::Create(raw_data_->ToArrayBuffer());
...
raw_data_.reset();
...
return result;
I'd imagine the effort/time/money it would take to replace those raw pointers with memory safe substitutes [2][3][4] (and enforce the ban going forward) would be relatively modest. Performance shouldn't be an issue [5].
Ug. After closer inspection, it looks like those particular raw pointers seem to be managed by a garbage collector. (Specifically, the "Blink GC" [1].) As others have pointed out, this particular bug may not actually be a C++ issue. (Or at least not a typical one.)
Not so sure. I haven't worked on this code for a while and have no non-public knowledge of the bug, but ArrayBufferBuilder does not inherit from any of the GCed base classes, and has the USING_FAST_MALLOC macro which is used for non-GC classes.
https://chromium.googlesource.com/chromium/src/+/refs/heads/...
ArrayBufferBuilder isn't, but DOMArrayBuffer seems to be a GC managed type [1], right? And, before the patch, the DOMArrayBuffer held a "refcounting pointer" potentially targeting raw_data_'s reference counted ArrayBuffer, right? I don't see any immediately apparent use-after-free with this, so I assume raw_data_'s ArrayBuffer is being messed with elsewhere? As someone who worked on the code, do you have an idea/hunch about where the invalid memory access actually occurs?
Yes, DOMArrayBuffer inherits via ScriptWrappable from GarbageCollectedFinalized<> so it's on the GCed heap. I don't understand the UAF yet, I'm hoping someone will write a blog post on it later :-).
Your claim that Chrome can be used a lesson in choosing programming languages is quite weak, because almost no one will build such a complex application and despite the risk all successful browsers still chose C++.
An application that:
a) has downloading and executing untrusted code as its main feature
b) supports a ton of media formats, with DRM to boot
c) is going through rapid changes, including adding very complex low-level features like WebUSB, WebGL or WebAssembly.
... will be insecure by design.
It's also very likely that no one will create a browser in C++ again, or in any other language for that matter. Microsoft recently gave up and decided to use Chromium, Opera gave up a long time ago. Chromium itself was forked from WebKit, which is used by Safari. Firefox is the only odd one out, slowly but surely sliding into irrelevance.
You've missed my point entirely. This is not a plea to Chrome to rewrite their browser. My post has nothing to do with browsers.
My claim is that Chrome is an interesting case study in the most hardened user-facing C++ codebase in the world being hacked because of memory unsafety.
I also think that the strawman argument you've made is extremely weak for other reasons. This whole "insecure by design" thing is nonsense - everyone stating this seems to not understand that multitenant systems have existed for ages, under far more difficult constraints. An example - AWS Lambdas colocate your code with other companies' on the same hardware - if this were such an impossible task, that wouldn't be possible.
But again, my argument is not about browsers, or even much about languages, and is merely me pointing out an interesting case where memory unsafety was the root cause of an attack, despite great efforts.
The culmination of your message was "Let's just collectively admit it, finally - you can't write safe C++ in a codebase this complex.", that's your point.
It's probably correct, but also meaningless as I mentioned, because:
a) most codebases aren't even nearly this complex
b) no one will likely write such a codebase again
So the entire "point" is just trivia. It can't be used to decide whether to program something in C++, it can't be used to decide whether to use Chrome, it's not actionable at all.
Frankly I'm peeved that a superficial comment triggered such a long discussion and monopolised the top spot in the thread instead of making space for technical explanations or more interesting discussion.
Isn't it more a case of "you have to do everything right to keep the attackers out, they have millions of attempts and only have to get one right once to beat you".
You can't write safe $ANYTHING for a codebase this complex.
I am yet to see someone who has worked on a codebase this complex disagree.
Security issues and crashes in general result from your program interacting with the outside world and something behaving in a way you did not account for.
What’s dishonest? No one has said language choice is a silver bullet for all classes of security vulnerabilities. The point under contention is that we have better options for memory corruption vulnerabilities in particular.
In other words we’re not talking about whether or not something will be totally safe, but rather safer. Perfect is the enemy of good.
Yes they can. Computers have been writing safe code in various languages for decades: they're called compilers/transpilers. Maybe this is one of those situations where we define AI as "things we don't know how to program yet": we said being good at chess would require intelligence, once computers got good at chess they became 'just tree search'. It sounds like you're imagining that automating programming requires some currently-unknown approach, when others would say it's 'just compiling'.
Of course, we need to tell the computer what code to write. We do that using a programming language.
It could be the same language (C++), but that seems a bit pointless. Furthermore, since C++ allows unsafe code, using C++ to tell the computer what we want means that we're able to ask for unsafe things (if we want to). That makes the computer's job ambiguous:
- Should it always do what it's told, and hence write unsafe code when asked? (In which case, it doesn't solve the "write safe code" task we're talking about)
- Should it always write safe code, and hence not always do what it's told? (In which case, where do we draw the line? Would it be valid to ignore all input and always write out `int main() { return 0; }`?)
We can avoid this ambiguity if we forbid ourselves from asking for unsafe things. In other words, providing a guarantee about the code that the computer writes is the same as providing that guarantee for the instructions we give it (i.e. the input programming language).
For example, if we don't want the computer to ever write memory-unsafe code, that's the same as saying we can't ever tell it to write memory-unsafe code, which is the same as saying that we should instruct it using a memory-safe language.
That way, it's possible for a computer to not only write safe C++ in a codebase of arbitrary complexity; but (more importantly) to write safe C++ code that does something we want, and the instructions specifying what we want can be arbitrarily complex.
A memory safe one. There are many of them. They could build their own if they chose to - they've built multiple languages in the past.
Picking a language for the Chrome team doesn't seem practical - we all know where your question is going to head.
The point is they have to not pick C++. Again, they've invested many, many millions of dollars into security. Let's not pretend that they're priced out of using another language.
I didn't say C++ was a bad choice and I've purposefully avoided making this another language war issue.
What I'm saying is that Chrome is an example of a project with more security funding than just about any other project out there, and it still can't save users from the footguns of C++.
I guess the question used the wording "should have written it in?", to which I said "a memory safe one", and that's not true. I'm not interested in making a judgment call on their initial choice - I totally get the decision, regardless.
> What I'm saying is that Chrome is an example of a project with more security funding than just about any other project out there, and it still can't save users from the footguns of C++.
You can certainly make that argument but this doesn't seem to really be a compelling example. They had one security issue caused by a use-after-free over a decade. That's... a pretty fucking stellar track record and does not at all scream "you cannot use this language safely!!!", now does it?
I would certainly argue for something like Rust instead if starting from scratch, though, but just because A is better than B doesn't make B unusable trash, either.
Well, that's not really a fair interpretation of my argument, I'd say.
My argument is:
* We have a production, widely used codebase
* This codebase is in C++
* This codebase has probably the most significant efforts to secure it of anything of its size, or at least it's in the top 5
* This codebase suffered enouguh critical vulnerabilities for users to be attacked in the wild
So let's be clear - Chrome suffers from thousands of memory safety vulnerabilities, but not many make it to ITW exploits. This case is special because users actually suffered because of it. It isn't fair to say they've had "one security issue", certainly, just one that's had major user impact.
I'm not judging C++ or the choice to use it. I am saying that this is an example of a very hardened system not being able to compensate for memory unsafety.
> not being able to compensate for memory unsafety.
This is a bit of a simplistic view tbh. They have managed to drive up costs for 0 days on the black market. They have introduced auto-updating browsers to get security patches to users quickly. They have managed to reduce the number of security exploits. This is a big feat and major progress.
They have compensated for memory unsafety quite effectively. Maybe not perfectly, but well enough.
Yes, memory safe languages are wonderful. I myself am a rustacean and LOVE to RIIR. But their efforts weren't in vain.
Should they start thinking about adopting a memory safe language like Rust or Wuffs? Definitely.
I think I've been very open about what an accomplishment they've made, and how proud they should be to have kept Chrome users safe for all of these years.
It is exactly because their efforts to secure Chrome are so impressive that I think this event is interesting.
None of what I've said is about Rust or even a suggestion that they shouldn't keep doing what their doing. One ITW exploit in a lifetime of a product is a great track record.
It is merely interesting to observe when herculean efforts fall down.
Not by a long shot either. The current stable version of Chrome (72) came with 58 security fixes, including a dozen UAFs, albeit several of those are in third party dependencies.
C++ is a write only language. Too many complex features that are used in ways that only the author of the code understands at the time of writing - or thinks of understanding at the time of writing even.
That doesn't mean that they (or anyone) should still be using it.
The choice of language 15 years ago has nothing to do with the languages that could be in use today on the same project.
Rust has `unsafe` all over the place; it's no more safe if you use that keyword to do the same things that are done in C++.
Get more compiler people on Go and it will be even faster than it is now (really fast), and Go is written in Go so there's no reliance on C++, unlike Rust.
> Rust has `unsafe` all over the place; it's no more safe if you use that keyword to do the same things that are done in C++.
Yes, it is, because the language has the concept of safe code to begin with. The problem with C++ is that all C++ code could potentially be unsafe.
> Get more compiler people on Go and it will be even faster than it is now (really fast), and Go is written in Go so there's no reliance on C++, unlike Rust.
This is a very confused comment. Rust is also written in Rust. If you're thinking of LLVM, sure, the Rust compiler uses that, but LLVM is nowhere to be found in products written in Rust that are shipped to users. What matters is how safe the runtime is, and there's no real difference between Go and Rust in this regard. Go might theoretically have some kind of edge over Rust in safety in that it calls syscalls directly instead of going through libc, but I highly doubt it matters in practice, because (a) the libc wrappers are a drop in the bucket compared to the complexity of the kernel; (b) Go only does that on Linux these days anyhow.
Yup, and besides, Go has the unsafe (https://golang.org/pkg/unsafe/) package, which allows for basically the same sort of unsafety as Rust's unsafe.
In fact, I would say Rust is typically more safe than Go, because in Rust you can mark any code as unsafe, it doesn't necessarily have to involve unsafe pointers. For example in Rust FFI functions are typically marked unsafe even if they don't involve pointers. There's no way to do that in Go.
Another example is strings: Rust ensures that strings are always valid UTF-8 by marking any function that could break that as unsafe. OTOH in Go you strings can contain invalid UTF-8 if I recall correctly.
My project currently has 104366 lines of Rust code and 174 uses of 'unsafe' (many of which are somewhat spurious, like usage of `mmap` and other system calls that don't have safe wrappers in external crates). My project does a lot of low-level stuff (e.g. ptracing, sharing memory with C++ code in other processes) and has lots of crazy low-level optimizations but still only has one use of 'unsafe' per 600 lines of code. I haven't made any particular effort to reduce usage of 'unsafe' either.
> it's no more safe if you use that keyword to do the same things that are done in C++
Sure, but using 'unsafe' everywhere that you would write unsafe C++ code simply isn't idiomatic Rust and except for very specific and limited situations, Rust developers don't do that.
> Get more compiler people on Go and it will be even faster than it is now (really fast), and Go is written in Go so there's no reliance on C++, unlike Rust.
You'll still be stuck with the fundamental tradeoffs that Go made like being GC'd and not having a fast FFI.
Those tradeoffs make sense in the target audience of Go (servers), but it's not going to make sense in something like a web browser.
Go has a garbage collector, and it's the fastest garbage collector that currently exists, by a wide margin, I believe.
When Go 1.8 released, it measured < 1ms garbage collection times on an 18GB heap, and that number has improved in the 2 years and 4 releases since then.
I don't believe that "it uses garbage collection" is a valid complaint against Go anymore, except in a real-time application, and I don't know of any real-time applications written in Go. I'm sure there are some, I just don't know of them.
Go's garbage collection is optimised for reducing GC pause times, and while it is extremely fast in this regard this is only one of many ways GC performance can be measured.
If for your workload GC pauses are tolerable and throughput is important (say when doing offline CPU bound batch processing) then the Go GC is not optimal for your use case and will be slower than other options on the market.
Some runtimes (such as the JVM) allow the user to pick from one of many GCs so that they can use the one that is most appropriate for their workload.
A fast GC doesn't mean the code wouldn't have been faster without a GC.
GC's prevent you from doing a huge range of techniques to improve cache locality or reduce allocation/free churn.
A simple example would be games will do things like have just a big allocation for all a frame's temporary data, and they just bump-pointer allocate from it. Then when the frame is over, they reset back to zero. It is already The Perfect GC. Bump pointer allocation, zero pause time, and perfectly consistent memory usage. No matter how good Go's GC gets it will always be slower than that.
At the other end of things you have things like LLVM's PointerUnion, where alignment requirements are (abused) to cram a type id into the lower bits of the pointer itself. Type-safe variant in the size of a void*.
> Go has a garbage collector, and it's the fastest garbage collector that currently exists, by a wide margin, I believe.
Fastest by what measure? I benchmarked some key value store implementation written in golang and ran into large (> 1 sec) latency spikes because the golang gc couldn't keep up with the large (10GB+) heap space. Java would have allowed me to select a GC algorithm that's best for my use case and I wouldn't have run into that issue.
golang's gc is tuned for latency at the expense of throughput, that's basically it. It's not some magic bullet that solved the gc issue, contrary to what the golang marketing team wants people to believe.
> Fuchsia team thinks otherwise, where kernel level stuff like the TCP/IP stack and IO volume handling are written in Go.
> Android team also makes use of Go for their OpenGL/Vulkan debugger.
Neither of those examples disagree with what I said. Fuschia's usage is the perfect example of agreement - Go specializes in IO (server workloads) and is then being used to do IO. That's a great usage of Go's particular blend of capabilities.
The use of GO in GAPID would be more interesting if it had any meaningful constraints on it, but it doesn't. It's an offline debugger for something that ran on a device with a fraction of the speed.
RenderDoc would be the meatier Vulkan debugger, and it's C++.
Sorry. Until Go gets its head out of its ass and gets proper generics Go will still be painful to use and slow. Not to mention with all the extra code complexity from writing everything with interface{}{} and reflection there are bound to be plenty of exploitable vulnerabilities. I honestly think it is worse than pre-generic Java because switching over the type of the variable is encouraged. Most sane type-checked languages kinda expect you to know what type you're working with at compile time.
Generics are slower, that's the trade-off. Developer time vs. execution time.
Saying Go has it's head up it's ass is extremely disrespectful to the people that created it and are maintaining it. You lost all credibility when you chose the low road and said that.
Look, there are core Go developers who admit that parametric polymorphism is a good idea. In fact, I'm not aware of anyone on the Go team arguing against that. Which is what you mean by "generics", right? In fact Go already has "generics" - maps, slices, channels. Are those "slow" in your opinion?
The only thing left to do is to propose a system that has reasonable trade-offs, doesn't suck, and doesn't completely break the existing language. Easy peasy!
I wonder who is doing Go more a disservice - people who hate everything about, or the blind fanatical devotees who think any criticism towards any aspect of Go is heretical.
Most generics work by monomorphisation, which basically means the compiler is doing a copy paste from int_btree.go to string_btree.go with the types changed. There is no runtime cost except text segment bloat. Generally modern compilers are smart enough to unify the identical machine code paths too, so you might not even get the code bloat.
> Generics are slower, that's the trade-off. Developer time vs. execution time.
You have no idea what you're talking about.
> Saying Go has it's head up it's ass is extremely disrespectful to the people that created it and are maintaining it. You lost all credibility when you chose the low road and said that.
No it's not disrespectful, it is entirely true. Do consider the origins of Go, where it all started as an experiment in combining bad decisions into a single programming language to see what would happen. What those very people didn't realize upon releasing it to the world is the sheer amount of people who fell for it, it was supposed to be a joke, with a stupid looking mascot and all... Now they have to take it seriously - and Google has to choose between keeping it alive or getting a forever bad rep for killing it - because too many companies rely on it, and they are forced to retrofit useful features on top of the giant pile of garbage they've created.
Yes, it is disrespectful, and no, it is not entirely true.
If you want to talk literally, a team has no ass to shove things into.
If you want to talk figuratively, making mistakes does not constitute having your "head up your ass." Even making multiple mistakes doesn't warrant that kind of statement. It's rude and it's pointless and doesn't add anything at all except to make you look asinine. So now you're just as asinine as I am with my misunderstandings. Well done.
(I'm going to ignore the personal attack and insult)
> If you want to talk figuratively, making mistakes does not constitute having your "head up your ass." Even making multiple mistakes doesn't warrant that kind of statement.
Making deliberate mistakes multiple times and resisting fixing them for 10 years does qualify as having their "head up their ass" (or asses if that's what you prefer).
I don't know about the origin story, although frankly I hope it's true.
Personally, I think Go is terrible. However, I can't imagine Google is even remotely considering scrapping Go. It is massively popular. It is used all over the place both externally and internally. It's a huge branding asset, community outreach tool, recruiting tool and provides leverage in the form of first party libraries over the direction that software development as a whole is going.
>Saying Go has it's head up it's ass is extremely disrespectful to the people that created it and are maintaining it. You lost all credibility when you chose the low road and said that.
Apart from memory safety issues, there are type safety issues that can cause equal security harm. Go's approach of casting interface{} back and forth is as dangerous as allowing malloc/free. The worst part is that the language designers don't see this as a problem.
interface{} is not great but it is not void *. Type assertions (casts) on interface{} are typechecked at runtime and failed type assertions on interface{} cannot violate memory safety.
Interface in Go can actually violate memory safety because of object slicing when racing on a variable concurrently from multiple goroutines (unless things have changed lately). It's two words (data and vtable) and so there is a tiny window in which one goroutine could change the data pointer while another goroutine is reading the two words, and so have a type mismatch that could probably cause arbitrary code execution in theory.
I've never heard of this happening in practice, however.
Unless I'm misunderstanding you, you're just talking about a garden variety data race on any interface value in shared memory right? If that's the case, I don't see what it has to do with interface{} in particular (or interfaces at all) as any multiword value in shared memory is susceptible to this, which is the unfortunate price you pay when your language supports shared memory concurrency but doesn't have any allowances for it in its type system.
Of course, data races are usually race conditions too, meaning that even if the memory corruption were prevented, there would probably still be a correctness bug to worry about, so I can understand why the Go authors chose the tradeoffs that they did.
Edit: Reread your comment and I get the part that is specific to interfaces now. This seems harder to exploit than, for example, a read of a slice header being... sliced... resulting in an out of bounds access.
Some languages guarantee memory safety even in the presence of data races (for example Java), while others simply prevent data races in their safe subset (rust). Go is normally memory safe but data races on some critical objects can compromise it.
Their egos have priced them out of a lot of stuff though.
The Chrome team is great but when you're surrounded by people who think they're god damn gods on Earth it's hard to question orthodoxies, especially old ones.
D would be interesting but it's also not memory-safe. Not strictly. You can restrict yourself to SafeD, but then you're stuck with a GC you don't really want. Or you can tag all your functions as @Safe, but then it's just a "best practice" and you can't do it everywhere because you can't do things like make system calls.
D has some interesting bits, but it did a lot of head-scratching stuff too. It seemed really confused about what target it was going after, like some middle ground between C#/Java & C/C++ that really doesn't seem to exist.
KHTML is the rendering engine for the Konqueror browser. Webkit is a fork of KHTML. And Chrome's engine is called Blink (it used to be Webkit, but they forked it).
Yes, the KHTML base for the rendering engine was started back in 1998, so C++ was a fine choice then. It's grown up as a code base significantly since then.
Nope. It's only true when all your code use safe subset/built upon a perfectly correct unsafe base (which is inevitable in a project like Chromium) with correct usage. Otherwise a single misused external call with unsanitized value can ruin all of your security guarantee.
Not really. It's been proved that if your unsafe foundations are correct and don't break the rules (i.e. their precondition is correct), then anything safe built on top of that is also correct.
Sure you could rely on a C/C++ library that causes problems, but then again you can either:
A) fix that library
B) replace that part with Rust or even stricter language.
There isn't a "safe or bug free" codebase in any language for any complex software project. The only code that you could possibly verify as "safe" are simplest of programs.
There is always a trade-off between complexity, security and performance.
What is a C/C++ programmer? I've written fairly large amounts of C/C++ over the course of my career and I continue to do so. I totally concur with this and am eager to see Rust take its place over time.
I was mainly a C and C++ developer until 2006 and you will see me praise C++, but also be an heavy critic of the copy-paste security exploits it inherited from C.
> According to the official release notes, this vulnerability involves a memory mismanagement bug in a part of Chrome called FileReader. That’s a programming tool that makes it easy for web developers to pop up menus and dialogs asking you to choose from a list of local files, for example when you want to pick a file to upload or an attachment to add to your webmail.
It sounds like the bug occurs interacting with external code, win32 or equivalent. Even if chrome were written in a "safe" language this section would likely be in unsafe block.
> Let's just collectively admit it, finally - you can't write safe C++ in a codebase this complex.
And so, as they say, we should all be using Rust. But allow me to explain why I don't yet.
Rust has one really outstanding feature -- a borrower checker that makes it memory safe. Adding that to C++ would be a compatibility-breaking change. So then, while they were at it, they changed lots of other things. It's a whole different language, separate syntax, generics that work differently than templates, different standard library, etc.
This interacts with the finite amount of time I have to learn a new language, making it take longer before I feel proficient enough in it to start using it for real work. Sufficiently long that the day that I do is still in the future.
I understand the desire to make changes. Many of the changes are improvements, and C++ can be ugly. But it's the devil we know. A version of it with the minimum necessary changes to add a borrow checker would have me using it already, and I expect I am not the only such person.
> Rust has one really outstanding feature -- a borrower checker that makes it memory safe. Adding that to C++ would be a compatibility-breaking change. So then, while they were at it, they changed lots of other things. It's a whole different language, separate syntax, generics that work differently than templates, different standard library, etc.
> I understand the desire to make changes. Many of the changes are improvements, and C++ can be ugly. But it's the devil we know. A version of it with the minimum necessary changes to add a borrow checker would have me using it already, and I expect I am not the only such person.
What you say would make sense if Rust were based on C++. I've never heard anyone say that.
I was under the impression that Rust is a derivative of ML, and (to me, at least) it looks very much like StandardML or OCaml with a borrow checker.
(I don't know C++, so I can't personally comment on how similar or different it is from Rust)
It's sorta kinda both. The original implementation was in OCaml, and many of the early developers were big ML fans. But we also tried to keep syntax more C-like, overall.
"It's a C-like OCaml" was how Rust was originally described to me, when I first heard of it.
Moreover, it doesn't matter what it is based on, it matters what it is trying to displace.
I am not really even criticizing Rust. Let it be what it is. Python isn't C++ either. All I'm saying is that if the goal is to increase the number of people using memory safe languages, adding a borrow checker to C++ would serve that goal.
(Also, I would really like to have a language with both a borrower checker and actual C++ templates.)
Template metaprogramming, variadic templates, integers as template parameters, etc. Even better would be constexpr user types as template parameters.
How about a language that embraces Turing-complete template metaprogramming as a thing to design in on purpose rather than something discovered after the fact to be more useful than anticipated. Have the utility without the ugly.
Cool, thanks! I think you'll be happy with Rust eventually; a lot of this is coming, likely this year. It's on the roadmap, though that has to be approved first. (The thing that isn't yet is variadrics, not sure when that'll happen.)
(And the reason it's taking such a while is that we are actually doing that...)
They are working on it. The analogue to the borrow checker in C++ is called the "lifetime profile checker" and (an incomplete version) is included in MS Visual C++, but last time I checked (in January) it seemed to still have too many false positives to be practical.
In the mean time, I think "the minimum necessary changes" to achieve memory and data race safety is to replace all your unsafe C++ elements (pointers, arrays, vectors, string_views, etc.) with compatible substitutes from the SaferCPlusPlus library [1]. You don't even need to replace them all at once. You can replace them incrementally and your code will continue to compile and run throughout the process. And where needed, maintain maximal performance as well [2].
which seems to have been motivated by "CVE-2019-5786: Use-after-free in FileReader. Reported by Clement Lecigne of Google's Threat Analysis Group on 2019-02-27".
That CVE is still reserved/non-public on the Mitre NVD though.
But DOMArrayBuffer::Create() here takes ownership of the memory from ToArrayBuffer(), so in the latter case of a smart pointer, the internal buffer of raw_data_ is immediately invalidated and its value becomes undefined after creating the DOMArrayBuffer. This is fine if file loading is finished at this point because raw_data_ is reset to nullptr, but if the load is partial, then the undefined value in raw_data_ will be reused to create another DOMArrayBuffer which is then accessible in javascript. Hence the use after free.
I'll attribute the root cause of this bug to unclear memory ownership passing in interface design.
This blog post is so watered down and manages to digress at every possible point that it is almost impossible to read. The only useful part of the text are the URLs.
Also, this:
> A vulnerability, or vuln for short, is a bug that makes software go wrong in a way that reduces computer security.
> Next time u c a shrt'd wrd u cn just ass. it's useful. B/c they r.
They aren't always useful but I've rewritten your sentence in what I would consider a minimally legible format for me... but that's the problem it's for me. Don't introduce jargon in an effort to reduce comprehension time, it almost never works if you consider the time to familiarize yourself with the jargon. So when you're writing a blog post about PHP feel free to sprinkle in some comments about var vars, when you're communicating with your team use all your internal jargon... but when publishing an article for wide consumption just write everything out clearly.
> But more to the point, 'vulns' seems like a very unnatural abbreviation. I would go with v11n (similar to i18n).
Please no. I really don't like that convention and would rather you just type out the whole word if that's the alternative. Worse yet, for some reason you've decided to end in `n` rather than `y`.
How can you dismiss the first four letters as an "unnatural" abbreviation, and then suggest inserting digits to represent the number of characters removed as an alternative? I'm not following that logic at all.
Oh please _please_ don't. i18n is a terribly obscure term with no implicit link to the actual word. This is a place where "naming things is hard" but for big concept chose short concise terminology while letting the details get lost in the verbose verbiage. Whenever I see i18n I just weep over the fact they didn't use the term "lang", internationalization is complicated and hard to shorten due to other meaningful jargon around it but there are better options than the dumpster fire which is i18n.
> Whenever I see i18n I just weep over the fact they didn't use the term "lang"
That's a bad idea because "lang" or "language" is already dangerously overloaded. People casually use it to mean any of (actual) language, locale (language + region (+ script, maybe)), script, or any combination of the above.
Until now you apparently haven't been keeping a busy person typing in chat into account. Now you can. This use case isn't unique to the vuln/vulnerability abbreviation, but plenty of others. Including confusing ones like "i left you a vm" (virtual machine? where?).
It's weird because when you read vulnerability (or at least when I say it) the first phoneme effectively becomes 'vun' - but in the abbreviated form one feels the need to mentally enunciate the 'l'.
Same here. It is used internally here as a written abbreviation, and we use it as a prefix in a numbering scheme to identify a certain category of defects, but I don't think I've ever heard anyone use it verbally.
Vuln is a common abbreviation in the security space - although, I dont appreciate parts of the sentence structure and how things are written in the article in general. Its difficult to read.
This write-up is not helpful and says nothing about how one would be infected. it just says it can do code execution but no evidence anyone has been infected in any way or how would would be infected. The worst 0day possible is un-sandboxed code execution that is activated by merely visiting a webpage or clickinig.
> Although information regarding CVE-2019-5786 remains scarce currently, Satnam Narang, a senior research engineer at Tenable, says it is a "Use-After-Free (UAF) vulnerability in FileReader, an application programming interface (API) included in browsers to allow web applications to read the contents of files stored on a user's computer." Some further digging by Catalin Cimpanu over at ZDNet suggests that there are malicious PDF files in the wild that are being used to exploit this vulnerability. "The PDF documents would contact a remote domain with information on the users' device --such as IP address, OS version, Chrome version, and the path of the PDF file on the user's computer" Cimpanu says. These could just be used for tracking purposes, but there is also the potential for more malicious behavior. The 'use-after-free' vulnerability is a memory corruption flaw that carries the risk of escalated privileges on a machine where a threat actor has modified data in memory through exploiting it.
That's conflating two unrelated issues. The issue reported by EdgeSpot is much less severe, and a Google engineer hinted that it may not even be a vulnerability. CVE-2019-5786 has nothing to do with PDF files.
ya don't gotta downvote me for reposting media coverage! I didn't write the article, if it's wrong, thanks for pointing that out. Just trying to see what there is about it to figure out what's going on, and help people reading skip a step, if you wanna tell us it's wrong, great!
If the Electron app never shows untrusted HTML with Javascript enabled, then it's not an issue. Generally, only Electron apps with arbitrary web browsing functionality would do that.
So attacker would still need to have some javascript loaded somewhere for it to work. If electron app displays user-generated content, XSS can help run a javascript payload, however.
I hope this doesn't qualify me for a "whoosh" of your joke, but wouldn't an RCE in Chrome run code as the current user? Or did you mean attack the domain admin's computer?
It was exploited before the vendor was aware; IMO that earns it a permanent "Zero-day" title. Obviously it's not currently a zero-day, given that we're hearing about it from the vendor.
The moniker is pretty paradoxical otherwise, the discoverer writing a post about a zero-day would make it no longer a zero-day.
I always thought it was from the patch date. As I understand it there are 1-days, and 2-days, where people rush to make exploits for released patches to capitalize on the lag time between patch availability and wide deployment (and also zero-days which were recently patched), which is why zero-day denotes that there has been no time since a patch is available (since there isn't one). So, I would say this was a zero-day up until the point Chrome released a patch, and as of now it's some low X-day.
0day refers to vulnerabilities. t0 is when a vulnerability is discovered. t1 is either when the vendor issues a patch OR it is exploited and t2 is when >50% of vulnerable systems have applied the patch.
tl;dr: something is 0day once it's discovered. It is no longer 0day once an action is taken with the vulnerability.
I assume it is 0day irrespective of who discovered it. It remains 0day until an action is taken to mitigate it. So you have 0day exploits being traded on various markets - those are exploits which are known to certain groups, but the affected party hasn't yet taken action to mitigate them (most likely because they don't know).
That's slightly inconsistent with the OP's interpretation because the vulnerability would be traded so it could be exploited (presumably), but by the OP's definition that would make it no longer be a 0day.
I think people who don't know what 0-day actually used to mean use it in a sense of "new security bug". Classically, no 0-day can by definition have a CVE, for example. But right now any new bug which is widely exploitable in the wild can be called in the press "0-day", despite the fix being released.
It is fast, responsive, has much better security history and architecture than all others, super convenient if you have multiple computers. I have absolutely no problems with Chrome, I already trusted my information with Google, so I always stay signed in as well, never had any issues.
Caveat: if something’s “free,” you’re the product. Google wants to pull as much metadata from you as possible. I don’t trust anyone who gives me something for free. I therefore limit how I use it.
I made my choices carefully and consciously. As I said, I entrusted Google with my data, my emails, pictures, history. I know that my data is never sold to anyone and always kept secure. Google is probably one of the most careful companies when dealing with private data in the world. I can delete or take a copy of it if I want as well.
Needless to say, I disagree with the "you are the product" polemic.
>Google is probably one of the most careful companies when dealing with private data
>private data
Ah, the fabled "metadata is not data" defense. Sadly, given the scale and pervasiveness of Google, observing meta-data and cross-referencing your activity with others' activities is good enough to deduce most of the valuable information about you with reasonably good reliability. And this data, both by itself, and also aggregated with other users', is "good enough" for any privacy-busting use.
A lot of people have Google / Gmail accounts, with which it integrates very well. Also, most people don't care about ads/tracking, as evidenced by the massive number of people who still have Facebook accounts. It is a leader in web standards and features (e.g. PWAs).
In my industry, it is a very secure solution (despite the vulnerability disclosed here), so it gets chosen for that reason.
I personally prefer Vivaldi (which uses Chromium), but I do choose Chrome over Firefox. I'm not sure if it's the UI or what, but it has never really stuck for me. The thing that would get me to move away from Chrome is if they broke the API for ad blockers.
I have made several attempts to switch to Firefox. But for me at least Firefox seems to crash about once a day. I don't think Chrome has ever crashed on me in about a decade of using it, and crashed tabs are extremely rare.
I've been using Firefox exclusively ever since it was Firebird 0.7, every day, on scores of computers using Linux and BSD and Windows from 95 to 10, and I just don't remember it ever really crashing. I'm sure it's happened at some point, but it's rare enough that I can't recall a single instance.
But I've never used it on macOS, so I'm guessing that's what you're doing. I hear the Mac port is worse than the others in terms of stability and performance. If true, that's a pity, but Firefox really is rock solid on other platforms.
I use it because my clients use it, and their customers use it, which means my client's website has to look and work perfectly in it. I also use Firefox on my second monitor, because it's my preferred browser.
Because Google (even just search and mail) is extremely popular, and they ran a relentless advertising campaign, persistently telling everyone to install Chrome, right on the front page among other places.
These faster release cycles haven’t been around since sandboxing was implemented but it feels strange when browsers are allowing known security holes to be around. It doesn’t seem like they are trying to patch many other bugs.
The Firefox Quantum update didn't work on my work machine; I had the choice of either using the LTS version or switch to Chrome, and I ended up switching to Chrome.
I’d like to use Firefox, but their lack of AppleScript supports makes that unfeasible. I could get past its atrocious performance, but not past a missing feature I require multiple times a day.
I don’t use Safari because it lacks other features. I can’t disable JavaScript on a per-site basis, and the content blockers are a joke compared to uBlock Origin.
Most other browsers are Chromium based, so might as well use Chrome.
i've tried firefox, and chrome is simply faster in what i've experienced. I've tried the newer firefox too.
Having my privacy stolen? The moment they do something malicious with the data they have, they are dead. I trust them with my data because I know how the world works. Facebook is so much more dangerous as far as privacy is concerned
That compatibility with different browsers is a big enough issue in 2019 to stop you from using Firefox is just a sad reminder of how far we’ve fallen. Used to be that we actually cared about stuff being usable across browsers, after what we experienced during IE’s dominance.
It’s also a testament to Chrome’s dominance -now-.
It's partly that, but it's also partly that the pace at which new standards of useful things get implemented (pre-ratification and post ratification) entails patchy support plus differing implementation decisions from under-specified standards. My favorite example area right now is all the fun that is CSP. Firefox supports the SecurityPolicyViolation Event, which is useful so that you can let non-power users know about CSP issues without having to open the console, except it's gated by a setting in about:config that is off by default. Additionally for CSP's report-uri endpoint, Firefox won't send up any cookies with a request to that endpoint (https://bugzilla.mozilla.org/show_bug.cgi?id=1506992) which sucks if the endpoint relied on authentication that way. Chrome just works, meanwhile, on both of these issues. (Of course personally, if something doesn't work in Firefox, then I just don't use that something, or if I really need to (e.g. test business feature), I use chromium for just that one thing.)
Note that you can also upgrade Google Chrome by going to he 3 vertical dots menu, Help -> About Google Chrome.
I reckon that’s a little less scary for inexperienced users than typing in an arcane URL into the address bar…
The vulnerability is in the browser’s code itself. If you have the stable channel for Chrome added into Linux, then you just have to run ‘sudo dnf update.’
Updating Chrome is a vaccination, which is great, but people already affected by this exploit need a cure. I'd like to know more about who was exploiting this and for what purpose, and how to undo it.
This looks bad for Google. EdgeSpot detected an in-the-wild exploit and told Google about this in December, but Google wasn't going to fix the bug until late April.
Google only released a patch early because the finder blogged about it.
Yeah, I was going to say... it would make zero sense for an attacker to waste a Chrome RCE 0day on tracking people who read academic books about Honduras!
Although, I'm not sure why they'd do that in the first place, even. Anti-piracy? Seems a lot of effort..
Chrome has probably invested > 1 billion dollars into their codebase at this point. Certainly >100million into security.
They sandbox their code aggressively. They build this project with security in mind from day 1 - it's been architected for it.
The Chrome security team(s) has a lot of power for a product security org.
They fuzz. They invent new fuzzers. They cluster their fuzzers.
They have a world class bounty program.
They have a world class research team for finding vulns.
They invent or otherwise aggressively adopt mitigation techniques.
But someone out there did it.
Their track record for security is something to really be proud of - this is the first public ITW exploit of its type that I am aware of. But users are getting owned because of, at the very least, a Use After Free vulnerability.
Let's just collectively admit it, finally - you can't write safe C++ in a codebase this complex.
edit: (From a post below)
To be clear, I'm not saying "Chrome should be rewritten in a memory safe language", I'm saying that Chrome is an excellent project to point to, say "Wow, no one does as much to secure a codebase as them", and to follow that up with "and they still got owned by UAF".