Hacker News new | comments | show | ask | jobs | submitlogin
Virtually Unlimited Memory: Escaping the Chrome Sandbox (googleprojectzero.blogspot.com)
129 points by weinzierl 8 days ago | hide | past | web | 49 comments | favorite





This is yet another use-after-free in C++ code. It's modern C++ code written by excellent programmers following state-of-the-art security practices. Smart pointers, lambdas, you name it: it's all there. Yet a critical memory safety vulnerability still slipped through the cracks.

This was because of base::Unretained, which extracts raw C style pointers out of nice, safe C++ wrappers. Unfortunately, this is still a requirement in the advanced C++ software.

I wish there was a nice way to remove a need for such things, like a weak pointer that work with unique_ptr, but I do not think it is possible to do this while preserving zero overhead implementation.

The only practical solution I can think of is a shared_ptr-like object limited to have unique_ptr semantics. This will have overhead, but it could be worth it for the security gains.


> like a weak pointer that work with unique_ptr, but I do not think it is possible to do this while preserving zero overhead implementation

I think the type of pointer you're asking for basically does exist. First, you want to distinguish the cases when you want a "full featured" weak pointer that can gracefully handle the destruction of its target object [1] (rarely the case), or you just want a non-owning pointer that detects when the prorammer screws up and lets the target object be destroyed prematurely [2].

The latter is essentially just a non-owning reference counting pointer. The optimizer should be able to discard matching increments and decrements of the reference counter in many cases.

> This will have overhead, but it could be worth it for the security gains.

The performance cost of avoiding "unsafe" C++ elements is measurable, but reasonably modest [3].

[1] https://github.com/duneroadrunner/SaferCPlusPlus#registered-...

[2] https://github.com/duneroadrunner/SaferCPlusPlus#norad-point...

[3] https://github.com/duneroadrunner/SaferCPlusPlus-BenchmarksG...


It kind of is, but requires a complete stack change.

Solaris on SPARC, iOS and eventually Android, all make use of memory tagging.

It doesn't cover all cases, but still better than not having it at all.


Note that the bug was caused by broken code that creates an unsafe, unretained reference to a smart pointer.

Which you do in C++ every time you use an &-reference.

True, but in this case the buggy code had to explicitly write "base::Unretained" because the callback system (base::BindOnce) performs additional checks.

But that's not modern C++ anymore–the whole point is to have RAII manage your pointer's lifetime so it doesn't dangle.

References are absolutely modern C++. There isn't a nontrivial C++ program in existence that doesn't use references.

Yes, and most of those references are to locals that are passed as arguments to function calls that will never take their address. In other words, it's pass-by-ref - which is perfectly safe - not pointers.

To obtain a reference to an object that is managed by a smart pointer, you would have to, at the minimum, explicitly dereference that pointer with *. In most cases, this also happens in an argument context, and the caller will maintain the pointer. It breaks when the pointer that's managing lifetime is a part of mutable state that the callee can touch somehow without returning - then it can cause the object to be freed while still holding a non-counting reference to it. At that point, you basically need something like Rust lifetime/ownership tracking to prevent such unsafe situations from happening.


While I agree with you, minimising the use of unsafe, specially among cargo.io libraries is still an issue.

There is still too much code that relies on it, that could have been written without such constructs.


> This is yet another use-after-free in C++ code.

Use-after-free is the least common case of CVE in C++ : https://resources.whitesourcesoftware.com/research-reports/w...


Hm, a few years ago when I was actively fuzzing stuff, UAFs were something like 20-30% of the crashes and one of the more exploitable memory corruption bug classes.

I will grant that the fuzzing targets were browsers, pdf readers, office suites and stuff which have some characteristics not shared by all C++ software.

In particular, a script engine and usually a way for “native” objects to get referenced or frobbed by scripting. Along with complex trees of object references, custom allocators, object pools etc.

I would have loved to have written a more substantive response but I didn’t want to download the PDF and check their analysis because they wanted to harvest my email.

What I can say is that a large proportion of real-world attacks where a hapless user gets pwned by a malicious file, document or script have a UAF somewhere down below as a root cause.

Not sure how UAF as a bug class got rated “least common” in their analysis? Would love to see some insight here, it doesn’t mesh at all with my lived experience but of course I could be missing something.


> I would have loved to have written a more substantive response but I didn’t want to download the PDF and check their analysis because they wanted to harvest my email.

huh, they didn't ask me for any email (or maybe ublock handled it).


Thanks, I should have tried harder, any old email will do.

After looking at the paper I think the issue is that they are counting CWEs assigned to CVEs, but CWE assignment to CVEs is not very granular / accurate.

For a contrasting point of view here’s an alternative reference:

“FreeSentry: Protecting Against Use-After-Free Vulnerabilities Due to Dangling Pointers” - https://pdfs.semanticscholar.org/3829/df26d4ce686251b9b50308... - “In 2011 and 2012, the most exploited memory errors for Microsoft products were use-after-free vulnerabilities. It was also the most exploited vulnerability for both Windows Vista and Windows 7 and is the most common type of memory error that occurs in Internet Explorer.”. Ok, that’s a bit old. Also why doesn’t it show up in the data?

In an unscientific sanity check (bit slow to do because on mobile) I am not sure UAF is getting all the credit it deserves in CVE classification.

For example https://www.cvedetails.com/cve-details.php?t=1&cve_id=CVE-20... is a UAF (https://www.exploit-db.com/exploits/46184) but is listed as CWE category 264 (permissions, privileges and access controls).

CVE-2017-8540 https://www.cvedetails.com/cve/cve-2017-8540 is also a UAF but is listed as CWE category 119 (memory corruption / code exec), ref: https://www.exploit-db.com/exploits/42088

I think I could find a lot more. CWE assignment to CVEs is not really an exact science. I suspect UAFs are getting under-counted because the bugs just went into “privesc” or “memory corruption / buffer overflow” buckets.


Hey xyzzy123, are you available for some freelancing on the subject?

Of course, rewriting in Rust is the only moral choice, right?

I wouldn’t say moral choice but watching these types of issues crop up again and again even when the original vulnerable code has been written and reviewed by people with impeccable credentials and with the best intentions should give pause to those who wish to pursue new development with fundamentally vulnerable technologies, especially when there are alternatives that exist where these problems are much less likely to happen.

We don't tear down every building when we update the building code. We just improve how we build the new ones.

Or we require people to bring it up to code when they do major renovations (seems more in line with the Firefox rewrite)

FF does abide by this rule in-fact. Almost every new component is written in Rust. https://wiki.mozilla.org/Oxidation

So a new browser?

Or periodic renovation to code on important components of e.g. the home envelope or electrical system.

If zero-overhead interaction with OS APIs would still require unsafe blocks and raw pointers, a Rust implementation won't be bulletproof either.

It's a complicated and huge codebase created by many people. It will have bugs.

When's the last time a Java codebase had a minor memory-handling mistake caused a bug that literally let an attacker inject their own code into the process?

I'm sure it somehow manages to happen here and there in Java code that's specifically managing data meant to be executed and a bug caused it to be mixed up with data not meant to be executed, but generally it's not something that happens in Java if you don't reach for APIs for starting programs. In C/C++, any code could potentially have any issue that disastrous. The fact that bugs enabled remote code execution can happen anywhere, not just near specific dangerous API calls or language features, is a uniquely C/C++ problem.


Just google "RCE Java":

https://www.darkreading.com/informationweek-home/why-the-jav...

You may also be interested in JNI. Java is also written in C or some such, so it can't escape the realties of that language. Even if it would not be, it would probably run some kind of JITted assembly.

https://heimdalsecurity.com/blog/java-biggest-security-hole-...

Unless you're talking about some platonic ideal of Java, real world implementations have memory bugs.

Bug enabled RCE can't happen anywhere in a C codebase. It's comparatively rare, too, to other classes of bugs, and depends on how much an attacker can control the input.


That first article is proving my point. RCE issues only happen in Java in code that unsafely uses specific APIs. In C/C++, a mistake in a basic for loop that writes values into an array can cause a RCE vulnerability. Any pointer being passed around and written to can cause a RCE vulnerability if it might possibly refer to already freed memory. It's often impossible to tell if a bit of code is safe by looking at it directly, and instead it requires a more holistic understanding of the program. In almost every other language, you can be reasonably confident a bit of code is safe if it doesn't use any code loading, deserialization, or unchecked memory manipulating APIs. The few parts that do use those kinds of APIs stand out and can be reviewed more easily.

>https://heimdalsecurity.com/blog/java-biggest-security-hole-...

I'm specifically talking about the rate and severity of bugs in non-malicious code. Java's sandboxing and plugin aspects were horribly flawed and were rightly put out to pasture.

>Bug enabled RCE can't happen anywhere in a C codebase. It's comparatively rare, too, to other classes of bugs, and depends on how much an attacker can control the input.

It's definitely not rare compared to the rate of RCE bugs in other languages. I'd be surprised if most C/C++ programmers who have written their own non-trivial programs haven't written at least one memory-mishandling bug that allowed RCE. I really don't think the fraction of Java programmers who have ever mis-used JNI or deserialization is nearly that high.


...and yet there's so many C++ programmers walking around telling themselves they're so special they can write correct C++ code, everybody else is just stupid, and C++ is still a good idea.

The bug is thinking we can sandbox and run arbitrary code safely. Java, Javascript, flash, and even intel have failed at this.

It would be nice if we could acknowledge this rather than rewrite everything again and still fail.


sandboxing may not be perfect, but it provides an important layer of protection. it takes effort to break out of a sandbox.

if the protections that sandboxing offered were so flimsy as to be a false sense of security, that would be an argument against sandboxing. but that does not seem to be the situation we're in.


And how do you want to write it? With 'safer' JVM based languages? Rust? Go?

C++ has the best memory model out there. Why do they want to extract raw C pointers from smart ones? This seems like a bad practice if you need to do that.


Any memory-safe language. Pick your favorite.

I knew about this unlimited memory for years Chrome uses all the memory it can get. This is why I was testing firefox the other day.



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

Search: