It’s time for a memory safety intervention
Memory safety won’t fix shell escaping bugs. Memory safety won’t fix logic bugs. Memory safety will not prevent an attacker who has obtained your HMAC key from forging a malicious credential that, when deserialized, can call arbitrary Ruby methods (yes, this was a real vulnerability in older versions of Rails). Memory safety will not prevent a federated identity system which uses XML-based credentials from accidentally running attacker controlled commands due to external entity processing (yes, this was a real vulnerability in certain implementations of SAML). A language which provides a memory safe model but binds to unsafe code is still vulnerable when calling into unsafe code.
Nobody disputes these things. Now that we have that out of the way…
Programming in C means you are using an unsafe memory model 100% of the time. It is the programming equivalent of trying to walk a tightrope over a lake full of alligators while trying to avoid getting electrocuted by dangling power lines. The slightest mistake in your arithmetic at any one place in the code can be the difference between a perfectly safe program and remote code execution.
Even if you’re off by just one byte.
Even if you allow an integer to inadvertently overflow.
It’s okay to program in C. It’s not okay to be a developer of a an infrastructural piece of software like curl and blow off memory safety as if it doesn’t matter.
Quoting the blog post:
C is not the primary reason for our past vulnerabilities
There. The simple fact is that most of our past vulnerabilities happened
because of logical mistakes in the code. Logical mistakes that aren’t really language bound and they would not be fixed simply by changing language.
Of course that leaves a share of problems that could’ve been avoided if
we used another language. Buffer overflows, double frees and out of
boundary reads etc, but the bulk of our security problems has not
happened due to curl being written in C.
A bold claim! And also an incredibly disingenuous one. Vulnerabilities aren’t some sort of fungible commodity: they have varying severities. I’m sure curl has had plenty of low-severity logic bugs! And while it’s completely true that curl has had critical vulnerabilities that would be possible in any language, this doesn’t change that fact that memory safety vulnerabilities in curl are among the most severe.
How long has it been since there was an announcement of a severe memory safety vulnerability in curl? Zero. (Well, more by the time you read this).
It’s 12:18AM. I wanted to start writing this post about an hour ago, but I couldn’t because I got home late and the first thing I did was patch OS X on my home laptop. Why? For among other reasons, this:
curl Available for: macOS Sierra 10.12.3 Impact: Maliciously crafted user input to libcurl API may allow arbitrary code execution Description: A buffer overflow was addressed through improved bounds checking. CVE-2016-9586: Daniel Stenberg of Mozilla
Note: this vulnerability was originally announced last December, but was not patched in OS X until yesterday.
curl is certainly not the only problem though. From APPLE-SA-2017-03-27-3:
AppleGraphicsPowerManagement Available for: macOS Sierra 10.12.3 Impact: A malicious application may be able to execute arbitrary code with kernel privileges Description: A race condition was addressed through improved memory handling. CVE-2017-2421: @cocoahuke AppleRAID Available for: macOS Sierra 10.12.3 Impact: A malicious application may be able to execute arbitrary code with kernel privileges Description: A use after free issue was addressed through improved memory management. CVE-2017-2438: sss and Axis of 360Nirvanteam Audio Available for: macOS Sierra 10.12.3 Impact: Processing a maliciously crafted audio file may lead to arbitrary code execution Description: A memory corruption issue was addressed through improved input validation. CVE-2017-2430: an anonymous researcher working with Trend Micro’s Zero Day Initiative CVE-2017-2462: an anonymous researcher working with Trend Micro’s Zero Day Initiative Bluetooth Available for: macOS Sierra 10.12.3 Impact: An application may be able to execute arbitrary code with kernel privileges Description: A memory corruption issue was addressed through improved memory handling. CVE-2017-2420: Pekka Oikarainen, Matias Karhumaa and Marko Laakso of Synopsys Software Integrity Group Bluetooth Available for: macOS Sierra 10.12.3 Impact: A malicious application may be able to execute arbitrary code with kernel privileges Description: A memory corruption issue was addressed through improved memory handling. CVE-2017-2427: Axis and sss of Qihoo 360 Nirvan Team Bluetooth Available for: macOS Sierra 10.12.3 Impact: An application may be able to execute arbitrary code with kernel privileges Description: A use after free issue was addressed through improved memory management. CVE-2017-2449: sss and Axis from 360NirvanTeam Carbon Available for: macOS Sierra 10.12.3 Impact: Processing a maliciously crafted .dfont file may lead to arbitrary code execution Description: A buffer overflow existed in the handling of font files. This issue was addressed through improved bounds checking. CVE-2017-2379: riusksk (泉哥) of Tencent Security Platform Department, John Villamil, Doyensec CoreGraphics Available for: macOS Sierra 10.12.3 Impact: Processing a maliciously crafted image may lead to a denial of service Description: An infinite recursion was addressed through improved state management. CVE-2017-2417: riusksk (泉哥) of Tencent Security Platform Department CoreMedia Available for: macOS Sierra 10.12.3 Impact: Processing a maliciously crafted .mov file may lead to arbitrary code execution Description: A memory corruption issue existed in the handling of .mov files. This issue was addressed through improved memory management. CVE-2017-2431: kimyok of Tencent Security Platform Department CoreText Available for: macOS Sierra 10.12.3 Impact: Processing a maliciously crafted font file may lead to arbitrary code execution Description: A memory corruption issue was addressed through improved input validation. CVE-2017-2435: John Villamil, Doyensec
This may look like a lot of vulnerabilities, but security announcements from Apple packed with remote code execution vulnerabilities and kernel-level compromises like this, for both OS X and iOS, are routine. As a security practitioner who reads these things regularly, seeing announcements with so many severe bugs can give one a fatalistic outlook, Nevertheless, many security experts including myself still point in particular to iOS as one of the most secure platforms.
How is this possible? The unfortunate answer is the whole apparatus of modern computing is built on a foundation that is fundamentally unsafe, and when we heap praise on iOS it’s only because it’s slightly less terrible than everything else.
Is it possible to write truly “safe” C code? Many C programmers will talk about all the tactics they employ: static analysis tools, valgrind, Coverity, etc. However, programmers utilizing state-of-the-art C tooling and best practices still constantly produce programs riddled with severe memory safety vulnerabilities. For all these tactics they are losing the memory safety war, because even with great tactics you can’t win a war with a bad strategy.
Flash back to 1995-2005 and C was my favorite language. As recently as 2013 I was shipping major projects in C (projects I was very happy and comforted to see rewritten in a memory safe language). I still think C has merit in certain applications.
But something needs to happen. For one, we can’t have developers of infrastructural projects like curl telling people that memory safety doesn’t really matter. Software like curl is installed on countless computer systems critical to people’s livelihoods. That’s reality. If you’re a developer of software like that, claiming memory safety doesn’t matter is willful negligence. It’s the programming equivalent of saying seat belts don’t save lives.
We need to collectively admit memory safety is a problem.
Is there a strategic solution to writing C we can definitively claim is memory safe? Yes, but it involves doing things like writing Haskell first, then writing C, and proving the C is equivalent to the Haskell. This was accomplished by the developers of the Security Enhanced L4 (seL4) kernel, who also proved the Haskell correct under a formal model (and vicariously, the C). How hard was this?
The overall size of the proof, including framework, libraries, and generated proofs (not shown in the table) is 200,000 lines of Isabelle script
Formal verification is not a tractable strategy for pretty much any day-to-day C development.
Where does that leave us? Well, for starters, with an awful lot of software written in C, and it’s not going away any time soon, despite how much some of us would like for everyone to just rewrite it in Rust.
Though I evoked the first step of the Twelve Step program, I’m not really a fan of it. So here’s my two step program for C programmers:
Step One: Admit memory safety is an intractable problem and even if you write a blog post boasting about how you have a zero Coverity problems policy a memory safety vulnerability in your software will literally be announced the same day.
Step Two: Investigate alternatives to C. This isn’t my typical “how to pick a programming language” advice, but I hope these are options C programmers may have considered:
- C++ isn’t memory safe, but used with modern conventions at least provides a safer programming model, along with abstraction features that make programming less error-prone (watch out for those UAFs though).
- Go is winning hearts and minds.
- Rust is the new kid on the block. It supports a wide variety of platforms, and might even run on that microcontroller you think can’t run anything but C.
- Edit: I almost forgot about Swift! It’s neat too.
I’m not saying you have to throw away all your C code and start over from scratch. But if you find, say, Rust to be useful, you can start writing new portions/subsystems of a program in Rust (which provides a zero-overhead FFI to/from C, as it uses the C calling model, and even has a neat binding generator). If you can even pull that off, your program has moved from being 100% unsafe to >0% safe, and in my book, that’s an accomplishment.
We need more memory safe code in the world, and we especially need it at infrastructural levels such a curl-like core utilities and operating systems.