-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
RFC: I/O Safety #3128
RFC: I/O Safety #3128
Conversation
Either way, creating an IO-safe random-access pointer to the mmap device file can mess up the memory safety of rust, right? |
A safe |
Ah, if you're talking about Linux's /proc/self/mem, yes, that can also break memory safety. Spawning a debugger process can too. These are independent concerns that don't cancel the usefulness of memory safety or I/O safety. |
Co-authored-by: Josh Triplett <[email protected]>
|
I view that like |
That could be done by passing a flag to |
It's true that one can reasonably say that anything to do with File and OpenOptions is arguably I believe the correct focus for That means it's not about whether the OS allows Rust to edit its own runtime memory, or even its binary code, but making sure that the authority to do so is obtained in a lawful manner obtained via File APIs. With an appropriate extension to the language, such as |
Several folks have expressed interest in seeing what a less minimalist change to I've now put together a prototype of such an API. The high-level summary is that it defines The prototype repo, with an example that supports Unix and Windows, is here: https://github.com/sunfishcode/io-experiment Feedback welcome! |
Yeah that looks great. :) Though I am a bit surprised by |
Also, my prototype doesn't yet deal with this yet, but Windows has multiple representations for optional handles. I'm not a Windows expert, but if I understand correctly, we may still be able to have |
I think it would just require setting the right EDIT: Oh, you are pointing to the FFI-compat lints. Yeah those would also need to be adjusted, indeed. (This is the codification of "documenting that we guarantee the appropriate ABI".) |
Users could still do |
@pickfire that's |
"Dereferencing" filedescriptors not obtained by functions implementing |
I've now removed the To support this, I added niche optimizations to the Windows types, so that Seeing how well |
iirc Windows has two different invalid values it uses inconsistently for handles: |
That's right; the blog post I linked to above has more info. io-experiment now deals with this, and documents which values are valid in each type, such as here for |
If possible, I think putting the |
I would like to air concern about churn. As far as I understand, when this RFC is implemented, more or less every current user of What eases the transition is the fact that There are some aspects that could make the transition troublesome though: First, there's little concrete, tangible benefit in migrating to the new APIs, as it mostly closes a loophole. Some library authors might see this as a needless churn, and refuse to migrate. If this happens, we will have both old and new style fd APIs in the ecosystem forever, sort of how we have both Second, my understanding is that, under this RFC, the Third, library crates usually have some sort of MSRV commitment and often support at least a couple of Rust versions: they'll have a choice between keeping API as is (and becoming unsound in Rust X + 1) or migrating to the new API (breaking compatibility with Rust X). The combination of the last two points feels especially concerning -- it seems like we might end up in a situation where we have a significant number of published API which "misuse" unsafe, but can't be immediately fixed. Several specific questions:
|
It's not just about closing a loophole but also ergonomics. Having lifetimes for fds means you can hand out an fd without having to manually ensure that it doesn't get closed prematurely. Currently when you're converting between different views on a file descriptor you have to ensure that all but one of the views flows into Plus it reduces the need for |
I think you're really underselling the benefits here. You're basically saying references and lifetimes over raw pointers aren't worth it. But I would disagree, and since you're using Rust I think/hope would disagree too. The whole point of this RFC is to bring (some of) the same safety guarantees we have for pointers and memory accesses to the I/O and file descriptors space. Yes churn will be an issue, it always is. But I would say the benefits outweigh the costs here.
All methods that use I'm not a security expert, but I don't think that warrants an CVE as there is no evidence that any of the API were actually used incorrect such that it can lead to an exploit, but again not a security expect.
The solution to this is of course library dependent. Speaking for myself, and thus the
We're already in that situation, this RFC proposes a fix. |
See https://internals.rust-lang.org/t/pre-rfc-i-o-safety/14585/7 for the "loophole" context.
This might be a false equivalence. We empirically know that raw pointers cause a lot of CVEs, even if you have RAII. To me at least, its unclear if IO-unsafety actually leads to CVEs in Rust. I don't remember ever seeing a bug in Rust due to fd re-use. The RFC text doesn't provide a list of the specific bugs that wouldn't have happened, had we shipped I/O safety in Rust 1.0. To me at least, in terms of impact IO-unsafety seems closer to |
I would say that the current situation around
I am solidly in camp "option 2" here. The fn AsRawPtr {
fn as_raw_ptr(&self) -> *const i32
} I hope we all agree that there is no reasonable safe Why do I claim that "raw FD" is akin to "raw pointer"? Two points:
I don't know why the
I think it is a pretty good equivalence, see above. Regarding actual evidence for bugs, Android had enough trouble with incorrect use of FDs that they invented a 'tagging'/'cookie' system to combat that. |
I'd say there are reasonable safe uses for struct AssociatedData<T: AsRawPtr> {
map: HashMap<*const i32, Data>,
}
impl<T: AsRawPtr> AssociatedData<T> {
fn get(&self, key: &T) -> Option<&Data> {
self.map.get(&key.as_raw_ptr())
}
} |
Okay, yes, there is a tiny list of things you can do. But that is an extremely niche case. To my knowledge, the overwhelming majority of code that abstracts over |
Having the option of fallible conversions is definitely a nice effect of that. Using the existing traits for also reduces the api surface significantly. It also seems consistent with A potential downside is that we can't add extra methods (with a default implementation) to the trait. Maybe at some point we'd want to add a If only we had a language feature that would allow us to make cc @rust-lang/libs-api |
APIs that make sense for all descriptors (there aren't many) could in principle be implemented on But once we have But the question is where would |
Or |
That's better but doesn't answer the question where such a helper would live. I guess we could make it an associated method on Or we could remove that future possibility if chained froms are good enough. |
I expect we could reintroduce trait FromFd: From<OwnedFd> {
fn from_into_fd<T: Into<OwnedFd>>(t: T) -> Self where Self: Sized {
let tmp: OwnedFd = t.into();
tmp.into()
}
}
impl<T: From<OwnedFd>> FromFd for T {} The only downside is that users would need to |
The final comment period, with a disposition to merge, as per the review above, is now complete. As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed. The RFC will be merged soon. |
Merging... |
The RFC has been merged! 🎉 Further discussion and ongoing work should take place in the tracking issue. |
Pre-RFC on IRLO
Raw OS handles such as
RawFd
andRawHandle
have hazards similar to raw pointers; they may be bogus or may dangle, leading to broken encapsulation boundaries and code whose behavior is impossible to bound in general.Introduce a concept of I/O safety, and introduce a new set of types and traits, led by
OwnedFd
andBorrowedFd
, to support it.[Edited to reflect changes to the RFC].
Rendered