-
Notifications
You must be signed in to change notification settings - Fork 13.1k
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
stdlib incorrectly handles O_PATH #62314
Comments
It does: https://github.com/rust-lang/rust/blob/master/src/libstd/sys/unix/fs.rs#L460. There's a fallback to support older kernels that you're probably running into: https://github.com/rust-lang/rust/blob/master/src/libstd/sys/unix/fs.rs#L469-L477 |
I figured out the reason why However, I would argue Rust still really shouldn't be using |
I just found another problem this causes -- let file = OpenOptions::new().read(true).custom_flags(libc::O_PATH).open(".")?;
let new_file = file.try_clone()?; // gives EBADF The patch to fix this issue is literally just: From 34a7c65154e2b49d6a58ec5883a3ee9a40289ab7 Mon Sep 17 00:00:00 2001
From: Aleksa Sarai <[email protected]>
Date: Sat, 6 Jul 2019 00:51:19 +1000
Subject: [PATCH] filedesc: don't use FIOCLEX on Linux
All ioctl(2)s will fail on O_PATH file descriptors on Linux (because
they use &empty_fops as a security measure against O_PATH descriptors
affecting the backing file).
As a result, File::try_clone() and various other methods would always
fail with -EBADF on O_PATH file descriptors. The solution is to simply
use F_SETFD (as is used on other unices) which works on O_PATH
descriptors because it operates through the fnctl(2) layer and not
through ioctl(2)s.
Fixes: rust-lang/rust#62314
Signed-off-by: Aleksa Sarai <[email protected]>
---
src/libstd/sys/unix/fd.rs | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs
index 6d23963e141a..0cecdd7ffa0b 100644
--- a/src/libstd/sys/unix/fd.rs
+++ b/src/libstd/sys/unix/fd.rs
@@ -175,6 +175,7 @@ impl FileDesc {
target_os = "emscripten",
target_os = "fuchsia",
target_os = "l4re",
+ target_os = "linux",
target_os = "haiku")))]
pub fn set_cloexec(&self) -> io::Result<()> {
unsafe {
@@ -187,6 +188,7 @@ impl FileDesc {
target_os = "emscripten",
target_os = "fuchsia",
target_os = "l4re",
+ target_os = "linux",
target_os = "haiku"))]
pub fn set_cloexec(&self) -> io::Result<()> {
unsafe {
--
2.22.0
I can submit a PR for this if that would be acceptable? |
Sure |
PR is here: #62425. |
All ioctl(2)s will fail on O_PATH file descriptors on Linux (because they use &empty_fops as a security measure against O_PATH descriptors affecting the backing file). As a result, File::try_clone() and various other methods would always fail with -EBADF on O_PATH file descriptors. The solution is to simply use F_SETFD (as is used on other unices) which works on O_PATH descriptors because it operates through the fnctl(2) layer and not through ioctl(2)s. Since this code is usually only used in strange error paths (a broken or ancient kernel), the extra overhead of one syscall shouldn't cause any dramas. Most other systems programming languages also use the fnctl(2) so this brings us in line with them. Fixes: rust-lang#62314 Signed-off-by: Aleksa Sarai <[email protected]>
…lexcrichton filedesc: don't use ioctl(FIOCLEX) on Linux All `ioctl(2)`s will fail on `O_PATH` file descriptors on Linux (because they use `&empty_fops` as a security measure against `O_PATH` descriptors affecting the backing file). As a result, `File::try_clone()` and various other methods would always fail with `-EBADF` on `O_PATH` file descriptors. The solution is to simply use `F_SETFD` (as is used on other unices) which works on `O_PATH` descriptors because it operates through the `fnctl(2)` layer and not through `ioctl(2)`s. Since this code is usually only used in strange error paths (a broken or ancient kernel), the extra overhead of one syscall shouldn't cause any dramas. Most other systems programming languages also use the fnctl(2) so this brings us in line with them. Fixes: rust-lang#62314 Signed-off-by: Aleksa Sarai <[email protected]>
I still do not see any fix for
Should I open an new issue for it? |
@rusty-snake Yeah, I forgot to write a fix for that. I can open a new issue for that... |
Are you kidding me? Yesterday I looked at the function where I needed this again after a year. And today I get a notifications here. Do you want to claim that coincidence exists?
SGTM |
There are several bugs here, but they all stem from the same problem -- the stdlib doesn't handle
O_PATH
correctly in a few places.O_PATH
requires you to set an extra (unused) mode.O_PATH
causes most other flags to be ignored, so requiring a mode is a little bit weird. Really,O_PATH
should probably be handled as anotherOpenOptions
mode.This one can be worked around pretty trivially (though it is a bit silly in my view), but unfortunately that's when you hit the next issue:
Rust uses
ioctl(FIOCLEX)
to set close-on-exec.This doesn't work with
O_PATH
becauseO_PATH
file descriptors haveempty_fops
which means that allioctl(2)
s on them fail (this is a security feature).Rust proactively sets close-on-exec in many different places, which means that any method that ends up triggering an
FIOCLEX
gives a spurriousEBADF
. The most obvious problem is withFile::try_clone()
but I'm sure there are plenty of other examples:Rust really should use
fcntl(F_SETFD)
becauseioctl(2)
s are blocked on allO_PATH
descriptors (whilefcntl
works without issue).The text was updated successfully, but these errors were encountered: