-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Safe methods in std::io allow reading uninit memory #20314
Comments
Nominating. Regardless of whether this technically violates Rust's memory safety guarantees, it's extremely surprising and has major security impact. |
It seems this was already noticed and the functions are suggested for deletion when |
As a side note this feels like what unsafe traits would be useful for. |
This was discussed as part of the IO reform RFC process, and it is believed not to lead to undefined behavior, at least if we follow a certain pattern of intrinsics use. Reading an uninitialized but alloced block of There doesn't seem to be widespread agreement elsewhere (on IRC, etc) as to how serious a security risk this poses. However, note that we can close this potential hole easily by pre-zeroing the memory in these convenience functions, without causing any API breakage. It would be helpful to see a more detailed example of an exploit based on the current behavior. |
I'm frankly astonished. There is no way my team will accept Rust with this How can you make any claim about type safety and security, with such a On Thu, Feb 12, 2015 at 2:07 PM, Aaron Turon [email protected]
|
First, I'm sorry if I wasn't clear, but no decision has been made here. I was asking for clarification. I was trying to clarify first of all that there is not a type or memory safety hole here, see this comment thread. If you believe this can lead to a type or memory safety violation, can you please spell out the details? (cc @mahkoh) Second, I was hoping you could spell out in more concrete detail an exploit based on this behavior alone. It would require a As I said in my comment, we always have the option of zeroing the memory in these convenience methods, which doesn't require any API change. |
I'm basically with @sivadeilra here. This needs to be fixed for 1.0. The exploit seems clear. The memory you read in You may not be worried about malicious
Sure, it's not UB. I'll even accept that it's not a "type and memory safety" issue. But this is a major lurking security risk in a language that otherwise goes out of its way to prevent you from reading uninitialized memory. |
But a read implementation doesn't read from the buffer, it writes into it. It would have to be very inept indeed to read from the buffer. |
No, it would just have to be a large software system with many components that interact in unanticipated ways. A |
There's no way I should have to write a "realistic" program and exploit to get people to take this seriously. But I'll do it if that's what it takes. Any read of uninitialized memory in the safe subset of Rust seems 100% not okay. It doesn't matter whether it's technically a "memory safety" issue. |
Argument by lack of imagination :) "Only two things are infinite, the universe and human stupidity, and I'm not sure about the former." |
I think you and @sivadeilra are reading way too much into my earlier comment: I'm trying to gain clarity here about the issues in concrete terms, because the original claim had to do with memory unsafety/UB, which turned out to be incorrect. I do take this seriously! Which is why I'm trying to understand the details.
This seems like the crux of the issue. There does not seem to be widespread agreement about this point, and I think we need to make a global decision about it. |
Yeah, screwing up the byte count seems more likely to happen than deliberately reading in the |
@kmcallister Thanks, that's what I was looking for! |
Sorry to pile on you @aturon, I know you're just fact-finding. I do have a pretty strong reaction to the "surely nobody would screw up that bad" logic, which is at odds with Rust's philosophy. |
OK, after discussion here and elsewhere, I propose we write a short RFC that clearly establishes the following policy, which goes beyond ensuring lack of UB: Safe APIs in Rust must never expose uninitialized memory, even in cases that do not lead to UB. @kmcallister Would you be interested in working together on such an RFC? |
I'll be honest, I was not following the full details of this discussion before. In particular, I mistakenly thought the focus was on the |
I am somewhat conflicted here, but I am happy to go along with this consensus. |
I've written an RFC to update our policy about safe code to cover this case. |
To me, this hole does constitute a type safety hole. "Type safety" is I believe many people have the perspective that conserving "type safety" Keegan's point about the composition of large, complex systems is very It is not important that this involves I/O. What's important is trusted It may be possible to have some cake and eat some. It may be possible to I would be extremely cautious about trading away a profound safety On Fri, Feb 13, 2015 at 10:18 AM, Keegan McAllister <
|
I think it's worth noting that this behaviour can be replicated in "user-space" by just reusing a fixed length buffer several times without zeroing in between (e.g. there was a recent blog post that described itself as demonstrating heartbleed in Rust by doing that sort of thing). Of course, it's definitely not as insidious as using uninit memory, since its relatively obvious from the source, while implicitly reusing an old allocation is very subtle and non-local. |
This commit alters the behavior of the `Read::read_to_end()` method to zero all memory instead of passing an uninitialized buffer to `read`. This change is motivated by the [discussion on the internals forum][discuss] where the conclusion has been that the standard library will not expose uninitialized memory. [discuss]: http://internals.rust-lang.org/t/uninitialized-memory/1652 Closes rust-lang#20314
This commit alters the behavior of the `Read::read_to_end()` method to zero all memory instead of passing an uninitialized buffer to `read`. This change is motivated by the [discussion on the internals forum][discuss] where the conclusion has been that the standard library will not expose uninitialized memory. [discuss]: http://internals.rust-lang.org/t/uninitialized-memory/1652 Closes rust-lang#20314
\src\libstd\io\mod.rs
contains two methods that allow attacking code to read memory that it should otherwise not have access to. The methods areReader.push()
andReader.push_at_least()
. An attacker could write (or exploit) an implementation ofReader
, by implementing aread()
method that reads from the given buffer, rather than writing to it. Or by not writing at all, returning a non-zero byte count, and then callingpush()
and seeing what memory was returned.The
push()
andpush_at_least()
methods should probably just be deleted entirely. The support functionslice_vec_capacity()
could also be deleted.The text was updated successfully, but these errors were encountered: