Abort a process when FD ownership is violated
When an EBADF happens then something else already touched an FD in ways it is not allowed to. At that point things can already be arbitrarily bad, e.g. clobbered mmaps. Recovery is not possible. All we can do is hasten the fire.
This commit is contained in:
parent
c5de414865
commit
38ded12923
@ -176,7 +176,20 @@ fn drop(&mut self) {
|
|||||||
// something like EINTR), we might close another valid file descriptor
|
// something like EINTR), we might close another valid file descriptor
|
||||||
// opened after we closed ours.
|
// opened after we closed ours.
|
||||||
#[cfg(not(target_os = "hermit"))]
|
#[cfg(not(target_os = "hermit"))]
|
||||||
let _ = libc::close(self.fd);
|
{
|
||||||
|
use crate::sys::os::errno;
|
||||||
|
// ideally this would use assert_unsafe_precondition!, but that's only in core
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
// close() can bubble up error codes from FUSE which can send semantically
|
||||||
|
// inappropriate error codes including EBADF.
|
||||||
|
// So we check file flags instead which live on the file descriptor and not the underlying file.
|
||||||
|
// The downside is that it costs an extra syscall, so we only do it for debug.
|
||||||
|
if libc::fcntl(self.fd, libc::F_GETFD) == -1 && errno() == libc::EBADF {
|
||||||
|
rtabort!("IO Safety violation: owned file descriptor already closed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let _ = libc::close(self.fd);
|
||||||
|
}
|
||||||
#[cfg(target_os = "hermit")]
|
#[cfg(target_os = "hermit")]
|
||||||
let _ = hermit_abi::close(self.fd);
|
let _ = hermit_abi::close(self.fd);
|
||||||
}
|
}
|
||||||
|
@ -870,6 +870,27 @@ fn next(&mut self) -> Option<io::Result<DirEntry>> {
|
|||||||
|
|
||||||
impl Drop for Dir {
|
impl Drop for Dir {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
// ideally this would use assert_unsafe_precondition!, but that's only in core
|
||||||
|
#[cfg(all(
|
||||||
|
debug_assertions,
|
||||||
|
not(any(
|
||||||
|
target_os = "redox",
|
||||||
|
target_os = "nto",
|
||||||
|
target_os = "vita",
|
||||||
|
target_os = "hurd",
|
||||||
|
))
|
||||||
|
))]
|
||||||
|
{
|
||||||
|
use crate::sys::os::errno;
|
||||||
|
// close() can bubble up error codes from FUSE which can send semantically
|
||||||
|
// inappropriate error codes including EBADF.
|
||||||
|
// So we check file flags instead which live on the file descriptor and not the underlying file.
|
||||||
|
// The downside is that it costs an extra syscall, so we only do it for debug.
|
||||||
|
let fd = unsafe { libc::dirfd(self.0) };
|
||||||
|
if unsafe { libc::fcntl(fd, libc::F_GETFD) } == -1 && errno() == libc::EBADF {
|
||||||
|
rtabort!("IO Safety violation: DIR*'s owned file descriptor already closed");
|
||||||
|
}
|
||||||
|
}
|
||||||
let r = unsafe { libc::closedir(self.0) };
|
let r = unsafe { libc::closedir(self.0) };
|
||||||
assert!(
|
assert!(
|
||||||
r == 0 || crate::io::Error::last_os_error().is_interrupted(),
|
r == 0 || crate::io::Error::last_os_error().is_interrupted(),
|
||||||
|
Loading…
Reference in New Issue
Block a user