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…
> Wasn't the heartbleed issue that you could trick it into reading past the memory it had allocated? No. Heartbleed is this: 1. malloc an input and an output buffer of the size specified by the caller (16 bits, up to 65536 bytes) 2. copy input data into input buffer (as little as 1 byte) 3. copy input buffer to output buffer 4. send output buffer to caller Neither malloc nor free zero-out their stuff, so when you mal…
Heartbleed in Rust
31–40 of 140 posts
Re: Heartbleed in Rust
#32Earlier quoted context omitted.
In Rust, you cannot ever read uninitialized memory (including allocated memory) without using unsafe code (as can be seen in the original code sample, the Rust buffer, unlike the C buffer, is initially zeroed out). So in safe Rust, what you are describing indeed could not happen. The unsafety would have to be explicit at the caller end: the unsafe within the allocator implementation isn't enough.
> So in safe Rust, what you are describing indeed could not happen. Read the last paragraph. OpenSSL has a buffer reuse system via a freelist (and the non-freelist code had bitrotted), it didn't release buffers to the system's allocator after use, buffers were initialised across calls. Otherwise while heartbleed would still have existed to a large extent, it would also have been mitigable by e.g. malloc.conf or shimm…
Re: Heartbleed in Rust
#33No 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. Heartblee…
That isn't true in Rust, and he had to basically implement a deliberately unsafe memory allocator to show this flaw. His argument that you can't say "no rust programmer would write this code" is flawed. Of course any programmer can write insecure code in any language. The point is that Rust makes it far less likely.
If he had ignored the custom allocator and used the defaults in both languages (e.g. malloc in C, whatever it is in Rust), then you would have seen the difference.
Re: Heartbleed in Rust
#34Wasn'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
#35Wasn'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
#36I 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…
Is this logic error or just misuse of memory? (The buffer array)
But AFAICT, in C it didn't even have the same buffer by design, it was reading uninitialized memory from whatever `malloc` gave it back - which is equivalent to allocating a new buffer in Rust.
Re: Heartbleed in Rust
#37No 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. Heartblee…
> What if the requester didn't actually supply payload bytes, like she said she did? What if pl really is only one byte? Then the read from memcpy is going to read whatever memory was near the SSLv3 record and within the same process.
Re: Heartbleed in Rust
#38Earlier quoted context omitted.
> So in safe Rust, what you are describing indeed could not happen. Read the last paragraph. OpenSSL has a buffer reuse system via a freelist (and the non-freelist code had bitrotted), it didn't release buffers to the system's allocator after use, buffers were initialised across calls. Otherwise while heartbleed would still have existed to a large extent, it would also have been mitigable by e.g. malloc.conf or shimm…
An allocator like that would require unsafe code to write and could not expose a safe interface unless it couldn't be used to read uninitialized memory. `Vec::with_capacity` would still not let you read the data even if you had a custom allocator.
Re: Heartbleed in Rust
#39Re: Heartbleed in Rust
#40Wasn'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…
> Wasn't the heartbleed issue that you could trick it into reading past the memory it had allocated? No. Heartbleed is this: 1. malloc an input and an output buffer of the size specified by the caller (16 bits, up to 65536 bytes) 2. copy input data into input buffer (as little as 1 byte) 3. copy input buffer to output buffer 4. send output buffer to caller Neither malloc nor free zero-out their stuff, so when you mal…
1. tls1_process_heartbeat() retrieves type and 16-bit length from the SSL record.
2. It stores a pointer to the payload (which is after the two length bytes).
3. For the response, it allocates an output buffer and memcpy()s from the payload pointer to the output buffer.
4. If the specified payload length (the two bytes preceding the payload) is less than the actual length of the payload, memcpy() will read past the actual payload in the SSL record and will copy arbitrary memory contents to the response.
This looks like a pretty traditional buffer overrun to me. As far as I can tell, nowhere in the code was the input ever extended to match the specified rather than the actual payload length and the fix was to insert a sanity check to abort if there's a mismatch.
[1] http://git.openssl.org/gitweb/?p=openssl.git;a=blob;f=ssl/t1...