Skip to content

Comment on Open-Sourcing ClusterFuzz

Comments

Makes you think about choosing to write software in C / C++ / other non-memory-safe languages when you need 25000 cores churning away to ensure you don’t make mistakes that could cause serious security issues.

It makes me wonder why Google wouldn’t put their efforts into using Rust, for example.

Of course, server power is cheap, but not for our planet.

I know some embedded/kernel devs and they don't take Rust very seriously. I don't think it has a lot of mindshare in industry among the kind of people who currently write C.

Even if all new code was written in safe languages we would still need to do fuzzing until all legacy code was rewritten -- operating systems, SSL libraries, browsers, load balancers, etc.

I know lots of embedded/kernel devs (I am one) and lots of them are at least interested in Rust. It does have mindshare.

I truly believe that's the only reason people aren't using Rust as a replacement for C / C++ immediately. The adoption isn't widespread, but I'm rather optimistic it will be.

It's getting there.

I don't think it's the only reason.

My C programmer friends like the dangerous features of the language and want to use them. Their programs are designed around the assumption that they can mutate anything in memory whenever they want to. They use mutable global variables. They would strongly dislike Rust's memory protections and ownership concept, and its other safety features.

To what purpose? It sounds like they are being reckless just for the heck of it, because that's how the big boys do it and they can't be bothered to learn a new skill.

Even if you use Rust (or other memory safe(r) languages), you still have a variety of failure modes that they don’t protect against, with which fuzzing may be helpful: poor resource handling (e.g. massive memory allocations), logic problems in program, busy loops, all kinds of assertions, exceptions, etc. triggering of which may lead to DoS, or other undefined behaviors. Sure: not as critical , depending your threat model , as remote code execution, but things that should be found and fixed from any code base that is part of something that people use.

Google is putting effort into using Rust, but in more greenfield work, like Fuchsia.

Integrating a new language into a new codebase is a lot of work; it would be great if Chromium started using it, but I also understand why it may be a harder sell there. Engineering is all about tradeoffs.

Well, don't most of their internal systems already run tooling that is already written using Linux and Gnu libraries? Wouldn't it make sense to do testing on what they already have available instead of some theoretical ground up replacement effort?

Not to say there isn't work on replacement efforts, only that testing what is in use is a practical thing, even if the scale is surprising.

It makes me wonder why Google wouldn’t put their efforts into using Rust, for example.

Well some newer projects in Chrome/Chromium are written in Rust so for what it's worth there is some effort.

I believe just yesterday the security team published a document which recommended avoiding unsafe languages for safety critical code: https://chromium.googlesource.com/chromium/src/+/master/docs...

I don't see Rust in the list of approved safe languages for chromium at https://chromium.googlesource.com/chromium/src/+/master/docs...

I don't think that's a list of approved languages but "likely candidates"?

But apologies perhaps I confused Chromium for Chromium OS: https://chromium.googlesource.com/chromiumos/docs/+/master/r...

Is there an actual list of approved languages?

Rust is listed a little higher in that link in the section about avoiding unsafe implementation languages. Given that they list it as a counterexample of things to avoid I would assume that means it is good, but that is no sure thing.

It's present in some newer projects, notably Fuchsia.

Have to say that nothing can make your program automatically safe (defined by common sense, not "memory leaks are also memory safe"[0]) without any effort, and the trend to claim some languages are inherently "safe" while others are not is definitely a hype. Modern C++ plus static analyzing (Chromium rolled out their own Clang plugins to do that) provides better flexibility.

[0]: http://huonw.github.io/blog/2016/04/memory-leaks-are-memory-...

Virtually nobody in security agrees with you. Memory-safe languages do effectively mitigate some of the most critical security issues.

C++ static analysis is helpful, but it is not memory safe. Modern C++ doesn't really help. In fact, in my opinion, modern C++ tends to be less memory safe than "classic" C++, because it adds all sorts of new fun ways to get use-after-free.

People drastically underestimate the prevalence and impact of UAF attacks. They're extremely common in complex applications and often lead to everything from information leaks to code execution. That's why almost every browser exploit (of the last ~10 years at least) uses at least one UAF in their chain.

That's why almost every browser exploit (of the last ~10 years at least) uses at least one UAF in their chain.

That's usually because the "low-hanging fruit" is mostly gone due to protections like stack canaries, CFI checks, address randomization, and sandboxing, which makes things like buffer overflows or jumping to shellcode more difficult.

Yet the Linux Kernel Self Preservation project is still in a getting there kind of state.

Sorry, what?

That low hanging fruit is not gone on the Linux kernel, for more info check Linux Kernel Summit 2018 and Linux New Zealand Conference 2019.

Modern C++ doesn't really help. In fact, in my opinion, modern C++ tends to be less memory safe than "classic" C++, because it adds all sorts of new fun ways to get use-after-free.

I think modern C++ is much safer than legacy C++, not by disallowing the USE after free, but by giving you the tools to make sure that the FREE happens at an appropriate time. A lot of this is not necessarily a feature of the language itself, but of idioms the community seems to agree to ie CppCoreGuidelines. I'm thinking of

- never use the delete operator manually, prefer std::unique_ptr

- prefer single ownership over shared ownership

- prefer immutable over mutable state

- ...

I agree with you that compared to Rust, this places a lot of burden on code reviewers and is in no way perfect, but I wouldn't say it's going in the wrong direction, making the language less safe.

When people use the delete operator manually and mess up, do they usually delete objects too early or too late? In my experience, they usually delete objects too late or not at all (though I admit to not having hard data here). Accordingly, most of the benefits people cite regarding RAII classes such as unique_ptr are that they reduce memory leaks. I would agree that they do. But memory leaks aren't nearly as severe as use-after-free.

Additionally, it's not really shared ownership that causes problems; it's the fact that references (and pointers) make it possible to violate ownership semantics. References are used all the time in C++, and you can't use any libraries without them. It doesn't matter if data has a single owner if that owner is deleted and you still hold references to the data. In fact, shared ownership via shared_ptr is safer than unique_ptr, from a UAF point of view.

Additionally, it's not really shared ownership that causes problems; it's the fact that references (and pointers) make it possible to violate ownership semantics.

Shared ownership makes it much harder to reason about lifetimes, increasing the chance of mistakes.

shared ownership via shared_ptr is safer than unique_ptr, from a UAF point of view.

Only if the dereferencing code holds the shared_ptr. It's also common to pass non-owning pointers to objects held by shared_ptr.

When people use the delete operator manually and mess up, do they usually delete objects too early or too late?

As you pointed out, problems arise if objects are deleted too early or twice. Double free is common in C and can be exploited as well...

I agree with you that compared to Rust, this places a lot of burden on code reviewers and is in no way perfect, but I wouldn't say it's going in the wrong direction, making the language less safe.

Well if it isn't getting any safer than the time-disproven technique of relying on human behaviour and there are automatically safer alternatives, then it is less safe than those alternatives.

That is the thing though, I never did code reviews in C++ projects and have been often in the past (in my C and C++ days) the dude playing the D.Quixote role about static analysers.

Modern C++ is safer, but only if you can ensure everyone on the team never reaches for C style tricks, nor the libraries that you link against.

Can a memory leak be the root cause of memory corruption? No: there has to have been some other problem, which is why it is worth separating it from other more dangerous "safety" issues.

Personal option: Separating leak from UAF and claim the former is more acceptable should not be the case, because leak applies to more than memory, and leaky fds can also create security holes like [0]

[0]: https://labs.portcullis.co.uk/blog/exploiting-inherited-file...

Accidentally "leaking" fds to a child process due to a resource leak would be a great example! However, I still feel memory/resource leaks are not the same as memory corruption. Memory corruption is more fundamental: it can be used to cause a leak, but a leak cannot be used to cause memory corruption. That is, being memory corruption-free is a necessary prerequisite for a program to also be leak-free (it isn't sufficient, though).

Additionally, that example doesn't seem to be a resource leak in the sense of a memory leak. The exact same problem occurs if the file description is purposefully used after the 'system' call (that is, it isn't being leaked by not being used again). That's an issue more with 'system'/'fork' implicitly inheriting file descriptors than a resource being leaked.

This is more of an issue with setuid (which has all sorts of problems) than with leaks. Note that this issue would still occur with C++, or in any GC'd language if the GC didn't happen to run before the call to system().

Also note that Rust has contained a mitigation for that issue for a long time now: https://github.com/rust-lang/rust/pull/24034

That kind of mitigation just makes me one step away from Rust - system programming languages should stick to the platform behavior, otherwise it's just another Python. Moreover this change is not documented anywhere else. Have a look at how GLib handle these cases[0]:

- during the GSubprocess discussion, I originally held the opposite opinion, but eventually became convinced (by Colin) to see the inherit-by-default behaviour of exec() as nothing more than a questionable implementation detail of the underlying OS. Consequently, at the high level, GSubprocess provides an API that gives the caller direct control over what is inherited and what is not, and that's just the way that it should be.
- this behaviour is not limited to GSubprocess. Closing all fds before calling exec() is a common practice in modern libraries and runtimes, and for good reason.

[0]: https://mail.gnome.org/archives/gtk-devel-list/2015-March/ms...

That kind of mitigation just makes me one step away from Rust - system programming languages should stick to the platform behavior, otherwise it's just another Python.

That's silly. The standard library of new systems programming languages should do the safe thing, not inherit all the mistakes of the OS that the OS can't fix due to backwards compatibility. If Unix were being designed today, I am certain O_CLOEXEC would have been the default. Besides, Rust's behavior matches what happens on Windows, and cross-platform consistency in the standard library is desirable.

In any case, what glib does matches what the Rust standard library does. The latter uses posix_spawn() directly in order to make sure no file descriptors are passed between parent and child. There is an API available to request file descriptor sharing explicitly.

AboutSource Built by g1lg1l

Hackerly is an independent reader for Hacker News, built on the public HN API. Not affiliated with Y Combinator.