Heartbleed on Rust

Original author: tedu
  • Transfer
In the comments on one of the links to Hacker News, someone claimed that using Rust would prevent Heartlbeed, that the code would not even compile. It sounded like a challenge!

The thread starts here . I was not going to find fault with anyone, but the statement about preventing Heartbleed turned out to be well formulated. Unlike vague statements about the safety of working with memory in general, this particular statement can be tested.

I do not plan to implement the entire TLS stack on Rust, so I will cut the path and reduce the scale of the problem. I hope that my model will retain the essence of the problem. In a nutshell, the goal is: to write a program that reads a file (package) from a file system (network) and sends it back (a kind of network version of echo). The length of the echo request will be encoded in one byte, followed by the data. This is equivalent to a TLS vulnerability. Our program will accept a couple of such packets, yourpingand myping, and respond with yourechoand packets myecho. If any data from the packet yourleaks into the packet my, we have a problem: heartbleed 1 .

Let's start with a simple Rust program.

use std::old_io::File;
fn pingback(path : Path, outpath : Path, buffer : &mut[u8]) {
        let mut fd = File::open(&path);
        match fd.read(buffer) {
                Err(what) => panic!("say {}", what),
                Ok(x) => if x < 1 { return; }
        }
        let len = buffer[0] as usize;
        let mut outfd = File::create(&outpath);
        match outfd.write_all(&buffer[0 .. len]) {
                Err(what) => panic!("say {}", what),
                Ok(_) => ()
        }
}
fn main() {
        let buffer = &mut[0u8; 256];
        pingback(Path::new("yourping"), Path::new("yourecho"), buffer);
        pingback(Path::new("myping"), Path::new("myecho"), buffer);
}

The program compiles, albeit with warnings due to lamer use std::old_io. God knows what code, but not the worst. For example, I managed to avoid using unsafe cross-language interfaces (FFI) to call memcpy from C.

Let's see what the program does with simple input.

$ echo \#i have many secrets. this is one. > yourping
$ echo \#i know your > myping
$ ./bleed
$ cat yourecho
#i have many secrets. this is one.
$ cat myecho
#i know your
secrets. this is one.

Bingo! Secret data leaked.

Of course, a true Rust programmer will never write such a program, so I probably haven’t shown Heartbleed in Rust yet.

Let's take a break from Rust and look at equivalent C code.

#include 
#include 
#include 
void
pingback(char *path, char *outpath, unsigned char *buffer)
{
        int fd;
        if ((fd = open(path, O_RDONLY)) == -1)
                assert(!"open");
        if (read(fd, buffer, 256) < 1)
                assert(!"read");
        close(fd);
        size_t len = buffer[0];
        if ((fd = creat(outpath, 0644)) == -1)
                assert(!"creat");
        if (write(fd, buffer, len) != len)
                assert(!"write");
        close(fd);
}
int
main(int argc, char **argv)
{
        unsigned char buffer[256];
        pingback("yourping", "yourecho", buffer);
        pingback("myping", "myecho", buffer);
}

The survey showed that no real C programmer would ever write such a program. What do we have?

code that no real programmer will write in C: heartbleed
code that no real programmer will write in Rust: (task for the reader)


The point of the post is not to blame Rust. I could write a similar program in Go, or even in Haskell, if I were smart enough to understand burritos . The point is, until we understand what vulnerabilities like Heartbleed are, we can hardly avoid them by simply switching to a magically vulnerable language. Yes, everyone has heard of Heartbleed, but that does not necessarily make him a good example.

Perhaps the argument about Heartbleed was used not as a reference to Heartbleed itself, but as a bundle of other big and terrible problems. Not sure if this makes the argument better. “Vulnerabilities like Heartbleed but not too similar” are a poorly defined class of problems. It is difficult to evaluate any statements about such a class.

Speaking about vulnerabilities and their resolution, we need to be precise and careful. The hype raised around Heartbleed (Shellshock, etc.) makes it an attractive target for constructing arguments, but it is worth checking the compatibility of the example and the argument. Erroneous examples lead to erroneous decisions.

Notes

1. bleed - oozing, emitting

References


Also popular now: