Heartbleed and static analysis

In the wake of the security disaster that is the Heartbleed vulnerability, a number of people have asked me if Coverity's static analyzer detects defects like this. It does not yet, but you'd better believe our security team is hard at work figuring out ways to detect and thereby prevent similar defects.

I'll post some links to some articles below, but they're a big jargonful, so I thought that a brief explanation of this jargon might be appropriate. The basic idea is as follows:

  • Data which flows into a system being analyzed is said to come from a source.
  • Certain data manipulations are identified as sinks. Think of them as special areas that data is potentially flowing towards.
  • A source can taint data. Typically the taint means something like "this data came from an untrusted and potentially hostile agent". Think of a taint as painting a piece of data red, so that every other piece of data it touches also becomes red. The taint thus spreads through the system.
  • A sink can require that data flowing into it be free of taint.
  • If there is a reasonable code path on which tainted data flows into a sink, that's a potential defect.

So for example, a source might be user input to a web form. A taint might be "this data came from a client that we have no reason to trust". A sink might be code which builds a SQL string that will eventually be sent to a database. If there is a code path on which tainted data reaches the sink, then that's a potential SQL injection defect. Or a source might be a number sent over the internet from a client, and a sink might be code that indexes into an array. If an number from an untrustworthy client can become an index into an array, then the array might be indexed out of bounds. And so on; we have great flexibility in determining what sources and sinks are.

Now that you understand what we mean by sources, sinks and taints, you can make sense of:

For the TLDR crowd, basically what Andy is saying here is: identifying sinks is not too hard1 but it can be tricky to determine when a source ought to be tainted. To get reasonable performance and a low false positive rate we need a heuristic that is both fast and accurate. The proposed heuristic is: if it looks like you're swapping bytes to change network endianness into local machine endianness then it is highly likely that the data comes from an untrusted network client. That of course is far from the whole story; once the taint is applied, we still need to have an analyzer that correctly deduces whether tainted data makes it to a sink that requires untainted data.

Taking a step farther back, I've got to say that this whole disaster should be a wakeup call: why is anyone still writing security-critical infrastructure in languages that lack memory safety at runtime? I'm fine with this infrastructure being written in C or C++, so long as at runtime the consequence of undefined behaviour is termination of the program rather than leaking passwords and private keys. A compiler and standard library are free to make undefined behaviour have whatever behaviour they like, so for security-critical infrastructure, let's have a C/C++ compiler and library that makes undefined behaviour into predictably crashing the process. Somehow C# and Java manage to do just that without an outrageous runtime performance cost, so a C/C++ compiler could do the same. With such a runtime in place, the Heartbleed defect would have been a denial of service attack that calls attention to itself, rather than silently leaking the most valuable private data to whomever asks for it, without so much as even a log file to audit.

To argue that we cannot afford the cost of building such a compiler and using it consistently on security-critical infrastructure is to argue that it would be cheaper to just deal with arbitrarily many more Heartbleeds.

Stay safe out there everyone.

  1. In the case of Heartbleed, a call to memset could be the sink.

ATBG: Why UTF-16?

I had a great time speaking at the Los Angeles .NET meetup Monday evening; thanks for the warm welcome from everyone who came out.

Today on the Coverity Development Testing Blog's continuing series Ask The Bug Guys I dive into the history of string representations in C# and Visual Basic to answer the question "why does C# use UTF-16 as the default encoding for strings?"


As always, if you have questions about a bug you've found in a C, C++, C# or Java program that you think would make a good episode of ATBG, please send your question along with a small reproducer of the problem to TheBugGuys@Coverity.com. We cannot promise to answer every question or solve every problem, but we’ll take a selection of the best questions that we can answer and address them on the dev testing blog every couple of weeks.

ATBG: Reordering optimizations

Last time on the Coverity Development Testing Blog's continuing series Ask The Bug Guys I discussed whether it was a good idea to remove a lock which protects an integer field. My conclusion was that it is not, because the lock prevents many potentially confusing optimizations. This week I follow up on that episode with an example where eliding locks on volatile reads and writes permits a surprising result.


As always, if you have questions about a bug you've found in a C, C++, C# or Java program that you think would make a good episode of ATBG, please send your question along with a small reproducer of the problem to TheBugGuys@Coverity.com. We cannot promise to answer every question or solve every problem, but we’ll take a selection of the best questions that we can answer and address them on the dev testing blog every couple of weeks.

ATBG: Can I skip the lock when reading an integer?

Today on the Coverity Development Testing Blog's continuing series Ask The Bug Guys, I answer a question that made its way to me from a Coverity customer: is it a good idea to remove a lock which only protects the read of an integer field? After all, that read is guaranteed to be atomic, so it seems safe. As is usually the case, the situation is unexpectedly complicated!1


UPDATE: A number of commenters have asked if marking the field volatile magically prevents reordering bugs. The specific problem with that proposal is that volatile reads and locks do not have the same semantics. A volatile read can be moved backwards in time with respect to a volatile write, and the x86 processor will actually do so, but a read, volatile or otherwise, cannot be moved backwards in time past the beginning of a lock. The more general problem is: we have a toy example that is greatly simplified from the real code, and therefore we don’t know what invariants the real code relies upon. Trying to deducing whether a real gun is safe by examining a toy gun is a dangerous proposition.

I have posted a follow-up article to address some of these concerns.


As always, if you have questions about a bug you've found in a C, C++, C# or Java program that you think would make a good episode of ATBG, please send your question along with a small reproducer of the problem to TheBugGuys@Coverity.com. We cannot promise to answer every question or solve every problem, but we’ll take a selection of the best questions that we can answer and address them on the dev testing blog every couple of weeks.

  1. Is "usually unexpected" an oxymoron?

Even more video

Here's another portion of the video interview that I shot over Christmas at Coverity headquarters in San Francisco.

In this bit I talk about the history of C#, how C#'s safety system is definitely a step in the right direction but not by any means a panacea, the most common defect patterns we find in C# code, the basic workflow for using the Coverity static analyzer, and finally a plug for this very blog. That's a lot to fit into seven minutes!

ATBG: How do exceptions interact with the "using" statement?

Today on the Coverity Development Testing Blog's continuing series Ask The Bug Guys, I answer a question I get quite frequently: what guarantees do we have about object disposal when the body of a using block is interrupted by an exception? The situation is rather complicated, it turns out.

As always, if you have questions about a bug you've found in a C, C++, C# or Java program that you think would make a good episode of ATBG, please send your question along with a small reproducer of the problem to TheBugGuys@Coverity.com. We cannot promise to answer every question or solve every problem, but we’ll take a selection of the best questions that we can answer and address them on the dev testing blog every couple of weeks.

ATBG: How does a lock work?

Today on the Coverity Development Testing Blog's continuing series Ask The Bug Guys, I answer a question I've gotten a fair number of times recently: how is it possible to implement locking without already having locking? 

The answer I give is chock full of lies, misinformation and oversimplification, but hopefully it will get across the basic concept that you can build all the threading mechanisms out of simple parts like atomic-test-and-set.

In related news, here are a couple of other recent posts to ATBG. First, my colleague Tim explains that Java's hashCode has many of the same design guidelines as the equivalent method in C# that I discussed here. And my colleague Jon discusses the perils of accidentally performing overlapping reads and writes to the same buffer in C. 1

As always, if you have questions about a bug you've found in a C, C++, C# or Java program that you think would make a good episode of ATBG, please send your question along with a small reproducer of the problem to TheBugGuys@Coverity.com. We cannot promise to answer every question or solve every problem, but we’ll take a selection of the best questions that we can answer and address them on the dev testing blog every couple of weeks.

  1. My favourite quotation on the subject of poor handling for overlapping buffers has to be "there has yet to be an example of an application whose impressive performance can be credited to the absence of overlap-detection code in memcpy". True that! I note also that the C# equivalent Array.Copy method is documented as dealing correctly with overlapping reads and writes to the same array.

Questions from Tuesday's talk

Thanks to everyone who attended our talk this morning. Apologies for the difficulties with the slides at the beginning. The slide sharing system we were using was being very unresponsive. Tomorrow should go more smoothly.

Speaking of which: tomorrow I'll be talking about the top five things I wish every C# developer knew; number three will touch your heart, you'll be shocked at number four and your dentist will hate number five. So tune in and learn how to improve your C# with one weird old trick.1 I'll also post a schedule of events for the live talk on Thursday once I've got it.

The talk was recorded; when we have the recording and slides available I'll post a link here.

Unfortunately we ran a little over – sorry – and did not have time for all the questions at the end. I’ll answer a few of the technical questions that did not get answered right now.

Continue reading

  1. This totally works on the rest of the internet!