-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Rust programs started with closed stdio streams may corrupt files|sockets|etc #57728
Comments
it appears that this is the conventional expectation of OS kernels. While I don't believe this should be allowed by the OS kernels, making Rust ensure that it doesn't use "reserved" file descriptors would break programs that rely on this corner-case. As this really is an OS level behavior, I think this needs input from OS Security architecture (SELinux, AppArmor, etc.) |
Kernel compliance or no, it doesn't seem okay to me that a program can open a |
This seems to be a known problem of the C/POSIX platforms at least as described in Secure Programming Cookbook for C and C++ chapter 1.5 |
I don't think there's anything we can do here. On Unix platforms, stdout is by definition file descriptor 2. |
We could check at startup whether FD 0/1/2 are open using I am not sure what we can do with this information, but I am not very familiar with the I/O parts of the standard library. |
If during startup we discover that any of those streams are closed, we can set a flag in the relevant |
As a data point,
As I've just realized and as Amanieu has pointed out,
|
You need to use |
Reopen standard file descriptors when they are missing on Unix The syscalls returning a new file descriptors generally return lowest-numbered file descriptor not currently opened, without any exceptions for those corresponding to stdin, sdout, or stderr. Previously when any of standard file descriptors has been closed before starting the application, operations on std::io::{stderr,stdin,stdout} were likely to either succeed while being performed on unrelated file descriptor, or fail with EBADF which is silently ignored. Avoid the issue by using /dev/null as a replacement when the standard file descriptors are missing. The implementation is based on the one found in musl. It was selected among a few others on the basis of the lowest overhead in the case when all descriptors are already present (measured on GNU/Linux). Closes rust-lang#57728. Closes rust-lang#46981. Closes rust-lang#60447. Benefits: * Makes applications robust in the absence of standard file descriptors. * Upholds IntoRawFd / FromRawFd safety contract (which was broken previously). Drawbacks: * Additional syscall during startup. * The standard descriptors might have been closed intentionally. * Requires /dev/null. Alternatives: * Check if stdin, stdout, stderr are opened and provide no-op substitutes in std::io::{stdin,stdout,stderr} without reopening them directly. * Leave the status quo, expect robust applications to reopen them manually.
For example, if a program is started with
./foo >&-
(stdout closed, stdin and stderr open),println!()
s fail silently (despitestrace
showing thatwrite(2)
clearly returns-1
andEBADF
). If a file is opened and then aprintln!()
is attempted, it silently writes into the file (which is probably not what was intended).Example 1:
Invocation:
target/debug/hello-world >&-
Expected result: panic, with an error message relating to being unable to write to stdout, exit code 101
Observed result: nothing (no output on stderr, exit code 0)
Example 2:
Invocation:
target/debug/hello-file >&-
Expected result: panic (as before), empty file
./foo
Observed result: no panic,
./foo
containsHello, world!
Rust version: 1.30.0
Platform: x86_64-unknown-linux-gnu
It looks like any Rust program which is started with one or more closed stdio streams, opens a file (or socket, or…), and subsequently tries to read|write said stdio stream will inadvertently read|write the file instead (messing up the seek position, not to mention causing data corruption). This seems like terribly bad behavior. ;-;
The text was updated successfully, but these errors were encountered: