-
Couldn't load subscription status.
- Fork 13.9k
Description
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 another OpenOptions mode.
let file = OpenOptions::new().custom_flags(libc::O_PATH).open(".")?; // gives EINVALThis 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 because O_PATH file descriptors have empty_fops which means that all ioctl(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 spurrious EBADF. The most obvious problem is with File::try_clone() but I'm sure there are plenty of other examples:
let file = OpenOptions::new().read(true).custom_flags(libc::O_PATH).open(".")?;
let new_file = file.try_clone()?; // gives EBADFRust really should use fcntl(F_SETFD) because ioctl(2)s are blocked on all O_PATH descriptors (while fcntl works without issue).