Live data from Hacker News

Heartbleed in Rust

tedunangst.com

11–20 of 140 posts

Re: Heartbleed in Rust

#11
post #3

Slightly OT: while trying to understand the vulnerability I came across a Rust question. Why can you do this? let mut outfd = File::create(&outpath); match outfd.write_all(&buffer[0 .. len]) { ... } According to `old_io::File`'s doc[0] it returns an `IoResult ` which is an alias `type IoResult = Result ` i.e. `Result `. How come you can do `write_all` directly on a `Result ` without unwrapping the `File` first? The e…

Line 21 here implements Writer for IOResult where T also implements Writer: https://github.com/rust-lang/rust/blob/master/src/libstd/old...

Re: Heartbleed in Rust

#12
post #10

Earlier quoted context omitted.

It's because Writer (the trait write_all() is from) is implemented on IoResult. http://doc.rust-lang.org/std/old_io/trait.Writer.html#tymeth... impl Writer for IoResult From the `std::old_io` docs: http://doc.rust-lang.org/std/old_io/index.html > Common traits are implemented for IoResult, e.g. impl Reader > for IoResult , so that error values do not have to be 'unwrapped' before use.

Ah, remote implementation of traits bites me once again. Is there any reason behind not listing the implemented traits in IoResult's docs? Listing the implementors in the trait is not very useful since in the first place you have to know which traits are implemented to consult them. It's backwards and counterintuitive as I see it.

In general, we're still working on a number of usability issues with Rustdoc's output. The one that bits the most people is methods through Deref. Luckily, this is just a tooling issue, a small bug to be fixed, rather than some sort of fundamental problem. The beta cycle is going to be all about polish, and issues like this are a good candidate for that kind of work.

Re: Heartbleed in Rust

#13
No true blogger would wilfully misunderstand a buffer overrun vulnerability in order to score some cheap pageviews.

To put it simply, his examples are the equivalent of doing this:

    unsigned char data[4096];
    #define X (*(int *)(&data[0]))
    #define Y (*(int *)(&data[4]))
    ...
Basically, he's explicitly re-using a buffer, no buffer was overrun. In Rust you will not read something out of a buffer you didn't put there first, in C you can, and you might even read several GB out of a 256 byte buffer.

Re: Heartbleed in Rust

#14
I mostly agree with the premise: logic errors are always going to be there, at least until the compiler is an IA strong enough to catch them for us (and by then we probably won't need coders anyway...). There's no silver bullet, bad coders are always going to produce. And I also don't like it when people claim that bug X or vulnerability Y wouldn't have happened if they had been technology Z, they're just begging for that type of post.

That being said I'm a bit more skeptical of this part: "code no true C programmer would write : heartbleed :: code no true rust programmer would write :: (exercise for the reader)"

If I look at the examples in the acticle, the C version doesn't look that terrible and contrieved to me. I wonder what the author means by "Survey says no true C programmer would ever write a program like that, either." That looks like a lot of C code I've read, there's nothing particularly weird about it.

On the other hand the rust version looks very foreign to me (and I've been writing quite a lot of rust lately). You basically have to go out of your way to create the same issue.

I guess my point is that while it's true that as long as there'll be coders there'll be bugs and security vulnerabilities it doesn't mean we shouldn't try to make things better. And in my opinion Rust makes it much more difficult to shoot yourself in the foot than plain C.

Re: Heartbleed in Rust

#15
post #7

Wasn't the heartbleed issue that you could trick it into reading past the memory it had allocated? That's different to explicitly reusing memory you've allocated without clearing it in between. The original claim was that rust would prevent the class of errors that caused Heartbleed. No one claimed rust would prevent you from writing a program with a different bug that just happens to exhibit similar behavior. Buffer…

Openssl uses their own memory allocator (since malloc is slow on big-endian x86 xenix or something) so they _do_ reuse memory without clearing it in between. Had they used the system malloc, it wouldn't have been vulnerable (on OpenBSD and probably elsewhere). Can rust prevent you from implementing your own (buggy) memory allocator?

Re: Heartbleed in Rust

#16

This is why I get a little uncomfortable when people suggest Rust fixes tons of security issues. Yes, it will fix some of them. No, just because a Rust program compiles doesn't mean that it won't have problems. Rust is _memory safe_. Nothing more, nothing less.

I feel like you're undervaluing memory safety. Memory safety prevents most (all?) exploits that lead to remote code execution. There can still be high level vulnerabilities, but guaranteed memory safety is a huge improvement.

Rust's type system can be used to prevent high level attacks too. For instance, if an sql library is set up properly, it can prevent sql injection by requiring inputs be properly sanitized.

Re: Heartbleed in Rust

#17

No true blogger would wilfully misunderstand a buffer overrun vulnerability in order to score some cheap pageviews. To put it simply, his examples are the equivalent of doing this: unsigned char data[4096]; #define X (*(int *)(&data[0])) #define Y (*(int *)(&data[4])) ... Basically, he's explicitly re-using a buffer, no buffer was overrun. In Rust you will not read something out of a buffer you didn't put there first…

> No true blogger would wilfully misunderstand a buffer overrun vulnerability in order to score some cheap pageviews.

You may want to read up on Ted, and realise that when he writes

> if we don’t actually understand what vulnerabilities like Heartbleed are

he's probably talking about you.

> Basically, he's explicitly re-using a buffer, no buffer was overrun.

Which is essentially what happened in heartbleed. Heartbleed was not a buffer overrun at any point.

Here's the tl;dr: during heartbeat, OpenSSL would malloc both input and output buffers at the caller-specified size (65536 bytes), copy a caller-provided input (1 byte) to the input buffer then copy the whole input buffer to the output buffer.

Anything beside the overwritten byte would likely be previously written data since neither malloc nor free zero out their stuff by default[0], essentially leaking 65k of random data every time.

This was compounded by OpenSSL doing its own memory management via freelists, making it even more likely interesting data would be present in the input "garbage" and precluding OS mitigations (such as BSD's malloc.conf framework[1]), not to mention the unmitigated (no freelist) codepath had bitrotted and didn't actually work even if you knew how to enable it[2]. Note that [1] and [2] are by TFAA, and that he's an OpenBSD and LibreSSL core contributor.

[0] http://www.seancassidy.me/diagnosis-of-the-openssl-heartblee...

[1] http://www.tedunangst.com/flak/post/heartbleed-vs-mallocconf

[2] http://www.tedunangst.com/flak/post/analysis-of-openssl-free...

Re: Heartbleed in Rust

#18
post #7

Wasn't the heartbleed issue that you could trick it into reading past the memory it had allocated? That's different to explicitly reusing memory you've allocated without clearing it in between. The original claim was that rust would prevent the class of errors that caused Heartbleed. No one claimed rust would prevent you from writing a program with a different bug that just happens to exhibit similar behavior. Buffer…

Openssl uses their own memory allocator (since malloc is slow on big-endian x86 xenix or something) so they _do_ reuse memory without clearing it in between. Had they used the system malloc, it wouldn't have been vulnerable (on OpenBSD and probably elsewhere). Can rust prevent you from implementing your own (buggy) memory allocator?

Yes, because we don't support custom allocators yet ;)

Re: Heartbleed in Rust

#19

I don't know that anyone claimed that a bug similar or analogous to heartbleed couldn't be reproduced in Rust. If they did, that was certainly an overstatement. I think more concretely people claimed that unreachable code yields a warning in Rust, which is absolutely true, but certainly not equivalent to saying something like a heartbleed bug would not happen. In general, Rust is fairly aggressive about linting for "…

I hadn't actually followed the link in the original post. I see that the claims there were slightly different than what I was thinking of. Nonetheless, I stand by what I wrote above.

In particular, while I of course agree with the author that one can write buggy code in any language, I also have found that following Rust's idioms leads to code that is less buggy. This is not unique to Rust: I've also had similar experiences in Scala and Ocaml. What Rust brings to the table is that it supports zero-cost-abstractions, doesn't require a virtual machine, and guarantees data-race-freedom (a rather useful propery).

Re: Heartbleed in Rust

#20
post #7

Wasn't the heartbleed issue that you could trick it into reading past the memory it had allocated? That's different to explicitly reusing memory you've allocated without clearing it in between. The original claim was that rust would prevent the class of errors that caused Heartbleed. No one claimed rust would prevent you from writing a program with a different bug that just happens to exhibit similar behavior. Buffer…

Openssl uses their own memory allocator (since malloc is slow on big-endian x86 xenix or something) so they _do_ reuse memory without clearing it in between. Had they used the system malloc, it wouldn't have been vulnerable (on OpenBSD and probably elsewhere). Can rust prevent you from implementing your own (buggy) memory allocator?

No (well, there is still work to be done on custom allocators, but it's planned). But given that Rust uses jemalloc by default, not the system allocator, it is substantially less likely that you will want to replace it with your own. You certainly can't do it without copious amounts of unsafe code (which is really rather unfortunate).
Post reply on HN