Heartbleed in Rust
tedunangst.com
Heartbleed in Rust
1–10 of 140 posts
Re: Heartbleed in Rust
#2Re: Heartbleed in Rust
#3Why 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 example in the docs does something similar:
let mut f = File::create(&Path::new("foo.txt"));
f.write(b"This is a sample file");
So I guess I'm missing something here.[0] http://doc.rust-lang.org/std/old_io/fs/struct.File.html#meth...
Re: Heartbleed in Rust
#4Rust is _memory safe_. Nothing more, nothing less.
Re: Heartbleed in Rust
#5Slightly 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…
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.Re: Heartbleed in Rust
#6Re: Heartbleed in Rust
#7The 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 overruns are tricker to spot than explicitly reusing a buffer.
[Edit] An example of an actual buffer overrun, with no changes to pingback.
C:
$:/tmp # cat bleed.c
#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)
Rust: C:\Users\ajanuary\Desktop>cat hearbleed.rs
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 panic!("say {}", what),
Ok(_) => ()
}
}
fn main() {
let buffer2 = &mut[0u8; 10];
let buffer1 = &mut[0u8; 10];
pingback(Path::new("yourping"), Path::new("yourecho"), buffer1);
pingback(Path::new("myping"), Path::new("myecho"), buffer2);
}
C:\Users\ajanuary\Desktop>hearbleed.exe
thread '' panicked at 'assertion failed: index.end Re: Heartbleed in Rust
#8Slightly 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…
> Common traits are implemented for IoResult, e.g. impl Reader for IoResult, so that error values do not have to be 'unwrapped' before use.
Re: Heartbleed in Rust
#9In general, Rust is fairly aggressive about linting for "small" details like unused variables, unreachable code, names that don't conform to expected conventions, unnecessary `mut` annotations, and so forth. I've found that these lints are surprisingly effective at catching bugs.
In particular, the lints about unused variables and unreachable code regularly catch bugs for me. These are invariably simple oversights ("just plain forgot to write the code I meant to write which would have used that variable"), but they would have caused devious problems that would have been quite a pain to track down.
I've also found that detailed use of types is similarly a great way to ensure that bugs like heartbleed are less common. Basically making sure that your types match as precisely as possible the shape of your data -- with no extra cases or weird hacks -- will help steer your code in the right direction. This is a technique you can apply in any language, but good, lightweight support for algebraic data types really makes it easier to do.
Re: Heartbleed in Rust
#10Slightly 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…
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.
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.