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].
True, but in this case the buggy code had to explicitly write "base::Unretained" because the callback system (base::BindOnce) performs additional checks.
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.
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.
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.
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.
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.
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.
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.
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.
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.
I've used Blogger on a semi-regular basis, say, once a month for countless years. It still receives occasional updates every now and then, last time last year if I remember correctly. So there's certainly maintenance crew assigned to it, even some new features have been added. I do agree that it's a pretty niche product in their lineup these days.
Personally I hope it goes away. I would like to see Google focus on enabling bloggers and site creators to host their own sites and work to build and automate open source projects into their cloud products. There are so many static site frameworks for bloggers at this point that it would be ideal for them to do something similar to Netlify and work on great themes for Hugo or other static site generators.
I'm going to guess around 99% of bloggers don't want to think at all about site creation and hosting. They want to buy/pick a theme, modify it a little, and focus on the reason they're there in the first place.
If you are going to rely on a 3rd party host why switch Blogger (which handles everything for you) with GitLab/GitHub (which requires a bit of extra maintenance from your side)?
AWS already provides hosting for static sites, as does Firebase. GitLab and GitHub both APIs. It really could be as simple as Blogger is today with little effort from Google. Building a community around static sites is nothing new. Jekyll, Hugo and many other static site generators have been doing this with embedded comments using Disqus and other providers. Hugo already provides internal shortcodes for all these features and more, as well as analytics. It is really just a matter of creating some great templates for people to start using and automating the deployment (or migration) portion of the website so that users that don't want to deal with any additional steps can do it from a single interface.