, Matasano 2007-07-12
Almost 10 years ago, during the dot-com bubble, I did what many security pros before and after me did and gave up on security to go do something meaningful [Ã¢??]. I was at Network Associates (after they bought Secure Networks), and David Meltzer, my alter-ego at ISS, recruited me into a startup along with Danny Dulai and Tim Newsham. We wanted to build the chat system of the future, and we ended up with application-layer multicast streaming media. In 1999. We were a bit ahead of our time [Ã¢??Ã¢??].
This is good to know because it will help you avoid ever starting a discussion with me about reliable multicast protocols (down with forward error correction!) or source-specific multicast routing (down with source-specific multicast routing!). But why I bring it up is, we wrote it in C++. We wrote a lot of C++. A lot. We used ACE. Used ACE before? You know how much C++ we were swimming in. A lot of C++. Template-y, Boost-y, Alexandrescu-understandingy C++.
Now this is a security blog, and so Im supposed to be using this time to make a point about security, and that point is this: the notion that C++ is a more secure language than C is a myth. C++ gives you a dynamically-resizeable string class, which makes it less likely that you are going to write the splitvt overflow. But it also gives you a dozen new features which, if you use them wrong, segfault your program.
Take exceptions. C++ has built-in support for exceptions; when something horrible happens, you throw a variable that any stack frame up the call chain can catch. This is better than returning a cryptic error code, because you cant forget to check it.
But. When you throw an exception, you effectively abort your current function, and all the functions in the call chain up to the point where the exception was caught. If any of these functions arent written to anticipate getting preemptively aborted, and hold on to a pointer or a chunk of memory, youve got a memory lifecycle bug.
This problem is well known to the C++ community. Herb Sutter wrote a famous article about it, which invented the notion of exception-safe C++ programming. Joel Spolsky wrote a JoelOnSoftware about it. Theres a debate about whether C++ exceptions are evil.
But its not well known problem to the security community. A year or so ago, Mark Dowd found yet another Sendmail vulnerability. Sendmail is written in C, not C++, but it uses Unix signals and longjmp to emulate C++ exceptions, and (its Sendmail, after all) isnt written exception-safe. You can trigger a timeout exception, and Sendmail will retain an invalid pointer into the stack that it would have cleared out if the exception hadnt occurred. That pointer can be used to scribble over stack frames.
Any time you have a language feature, and you have to think about writing code to be that-language-feature-safe, you have a security problem. Because that feature is creating bug classes. Bug classes are bad. Splitvt? Thats a bug. Stack overflows? Bug class. Stack overflows cost the industry over $700MM. Exception-safety problems? Bug class. One that C++ introduces.
Want another example? Destructors. Mark Dowd and John McDonald wrote a blog post about it a few months back. Do you audit code at your job? Its one of the top #10 most valuable blog posts of the year. Long story short? If you call delete instead of delete - which is an exceedingly common C++ error - youve introduced a potential vulnerability. Like integer overflows, a bug class.
Heres another example: the STL. STL (or, more properly, the Standard C++ Library) is the collection of container classes C++ provides. In C, if you want a hash table, you have to implement it yourself. In C++ - bad example. But if you want a red-black tree with the same API as a hash table, its provided for you. Also linked lists, resizeable arrays, and something called a dequeue (prounced woon). The STL is one of the great features of C++.
Its also a reliability disaster. Heres why: STL containers try to hide pointers from you. Instead of pointers, you get iterators, which are objects with a variety of interesting methods and generic functions that operate on them and all sorts of other fancy gunk and at the end of the day its all just 1500 lines of C++ template code wrapping: a pointer.
STL tries to avoid the most common pointer bugs, like walking off the end of an array into bad memory. But some bugs cant be avoided. So for instance: if you modify an STL map (which is a red-black tree), you invalidate all your outstanding iterators. Modifying a red-black tree potentially repositions the nodes they pointed to, and all that fancy OOP gunk aside, iterators are just pointers, not magic. If you hold references to those invalid iterators, they now point to invalid addresses.
This is an absurdly common problem. Im an OK developer, if I do say so myself, but Danny Dulai, Kneel Fachan, and Tim Newsham are just fucking insanely talented developers and they ran into these problems, just like me.
And again, this problem is well known in C++-world (theres a whole very excellent book about it). But its not well known in the security community. And when you screw it up, its potentially exploitable.
C++ gives you a resizeable string, so you wont write splitvt. But in 2007, code vulnerabilities dont look like splitvt anymore, ever. Weve moved on, through off-by-one errors into integer overflows and now uninitialized variables. On balance, the bug classes C++ introduces are way scarier than the ones it takes off the table.
So, to kick off our series of posts about which Black Hat talks you should be going to this year, Im going to recommend this one. Mark Dowd and John McDonald, on stage, talking about the ways C++ screws software security that you hadnt thought of before. Recommend is an understatement. If you get paid to find vulnerabilities in code, this is the most valuable talk at the conference this year.
See you there!
[Ã¢??Ã¢??] This is marketing-speak for wrong; you can say the same thing for a batters swing when he takes a strike.