Printer-friendly version: While My Heart Gently Bleeds
I look at the world and I notice it’s turning / While my guitar gently weeps
With every mistake we must surely be learning / Still my guitar gently weeps
—”While My Guitar Gently Weeps”, George Harrison
The “Heartbleed” SSL vulnerability existed since the release of OpenSSL 1.0.1-beta in January 2012. The flaw was not discovered and fixed until version 1.0.1g in April 2014. A missing check on the client-supplied buffer size for a TLS heartbeat made it possible to retrieve 64k of memory from of a vulnerable system without leaving a trace. (Details, Analysis)
/* From ssl/d1_both.c;
* also appears duplicated in tls1_process_heartbeat() in ssl/t1_lib.c
*/
int
dtls1_process_heartbeat(SSL *s)
{
unsigned char *p = &s->s3->rrec.data[0], *pl;
unsigned short hbtype;
unsigned int payload;
unsigned int padding = 16; /* Use minimum padding */
/* Read type and payload length first */
hbtype = *p++;
n2s(p, payload);
pl = p;
/* ...snip... */
if (hbtype == TLS1_HB_REQUEST)
{
unsigned char *buffer, *bp;
int r;
/* Allocate memory for the response, size is 1 byte
* message type, plus 2 bytes payload length, plus
* payload, plus padding
*/
buffer = OPENSSL_malloc(1 + 2 + payload + padding);
bp = buffer;
/* Enter response type, length and copy payload */
*bp++ = TLS1_HB_RESPONSE;
s2n(payload, bp);
memcpy(bp, pl, payload);
The code introducing the vulnerability was reviewed, then merged into OpenSSL with no tests added by the commit–demonstrating that code review, while important, is not sufficient to catch all serious bugs. Some have asserted that the bug could have been found with a small unit test, while others assumed it would have required a system-level test. The proof-of-concept Heartbleed unit test proves that a small unit test could have been written to detect the bug, or could have accompanied its fix to verify it and prevent a regression.
While it is easier to write the test after knowing where to look for the bug, a unit testing culture would have likely required a series of smaller, well-tested changes for the original feature, greatly increasing the probability that the flaw would have been discovered early. This is because good testing practice involves testing invalid inputs as well as valid, and good code review practice would require such cases to be covered by tests. People used to such a culture would be more sensitive to invalid input issues and mindful of how to test for and avoid them. As doctors wash their hands before surgery to prevent deadly infections, unit testing security-critical code can help prevent catastrophic vulnerabilities.
As many of us know by now, applying unit tests to an existing code base is a solved problem. The only thing standing in the way of fixing preventable bugs like this before they ship is the cultural bias against unit testing, either because it is not considered, not taken seriously, or is outright dismissed. Along with the Apple SSL bug, the Heartbleed bug provides another prime opportunity to demonstrate the value of unit testing to the entire tech community.
The OpenSSL team has provided a great service to the tech industry for years with an otherwise exemplary track record; as a result, many have excused the Heartbleed bug due to the small, all-volunteer team being understaffed and underfunded. However, in light of Heartbleed, we must not dismiss one of the most serious computer security flaws in years as unpreventable. We can help Open Source projects not just by contributing features, fixes, and money, but also by demonstrating how to provide better unit testing–by contributing unit tests to Open Source projects and writing blog posts, journal articles, etc. Given the availability of the open-source code, each one of us can help to seize such precious opportunities to fix the problem of severe, undetected, preventable bugs.