mirror of
https://github.com/openai/codex.git
synced 2026-10-31 19:28:49 +00:00
## Why Concurrent tests can reuse a closed file descriptor number, causing cleanup assertions that require `EBADF` to fail even when the inherited directory descriptor was closed. ## What changed Capture the inherited directory's device and inode before mount verification. Check `/proc/self/fd` afterward and accept either a missing descriptor or one referring to a different inode, while still rejecting a leaked descriptor to the original directory. Apply this check to successful verification and rejected mount markers. GitOrigin-RevId: 42ff3aebcee9c37c481772f8a425a8643708c426
131 lines
5.6 KiB
Rust
131 lines
5.6 KiB
Rust
//! Check mount validation and cleanup without assuming closed descriptor numbers stay unused.
|
|
|
|
use super::verify_fd_mounts;
|
|
use pretty_assertions::assert_eq;
|
|
use pretty_assertions::assert_ne;
|
|
use std::fs::File;
|
|
use std::fs::Metadata;
|
|
use std::os::fd::IntoRawFd;
|
|
use std::os::fd::RawFd;
|
|
use std::os::unix::fs::MetadataExt;
|
|
|
|
// Another test can reuse the number after closure; only the original directory is a leak.
|
|
#[track_caller]
|
|
fn assert_inherited_descriptor_closed(descriptor: RawFd, inherited: &Metadata) {
|
|
match std::fs::metadata(format!("/proc/self/fd/{descriptor}")) {
|
|
Ok(current) => assert_ne!(
|
|
(current.dev(), current.ino()),
|
|
(inherited.dev(), inherited.ino()),
|
|
"the inherited directory descriptor must be closed"
|
|
),
|
|
Err(error) => assert_eq!(error.kind(), std::io::ErrorKind::NotFound),
|
|
}
|
|
}
|
|
|
|
/// A matching mount authenticates its original inode and closes the inherited descriptor.
|
|
#[test]
|
|
fn matching_mount_closes_inherited_descriptor() {
|
|
let root = tempfile::tempdir().expect("temporary directory should be created");
|
|
let descriptor = File::open(root.path())
|
|
.expect("directory descriptor should open")
|
|
.into_raw_fd();
|
|
let descriptor_path = format!("/proc/self/fd/{descriptor}");
|
|
let inherited = std::fs::metadata(&descriptor_path)
|
|
.expect("inherited descriptor metadata should be accessible");
|
|
let marker = format!("{descriptor}:{}", root.path().display());
|
|
|
|
verify_fd_mounts(&[marker]).expect("matching mount should verify");
|
|
|
|
assert_inherited_descriptor_closed(descriptor, &inherited);
|
|
}
|
|
|
|
/// A swapped destination fails closed without leaking the original descriptor.
|
|
#[test]
|
|
fn mismatched_mount_closes_inherited_descriptor() {
|
|
let source = tempfile::tempdir().expect("source directory should be created");
|
|
let destination = tempfile::tempdir().expect("destination directory should be created");
|
|
let descriptor = File::open(source.path())
|
|
.expect("source directory descriptor should open")
|
|
.into_raw_fd();
|
|
let descriptor_path = format!("/proc/self/fd/{descriptor}");
|
|
let inherited = std::fs::metadata(&descriptor_path)
|
|
.expect("inherited descriptor metadata should be accessible");
|
|
let marker = format!("{descriptor}:{}", destination.path().display());
|
|
|
|
let error = verify_fd_mounts(&[marker]).expect_err("different inodes must be rejected");
|
|
|
|
assert_eq!(error.kind(), std::io::ErrorKind::PermissionDenied);
|
|
assert_inherited_descriptor_closed(descriptor, &inherited);
|
|
}
|
|
|
|
/// A symlink to the original inode is not itself the authenticated mount.
|
|
#[test]
|
|
fn symlinked_mount_destination_closes_inherited_descriptor() {
|
|
let root = tempfile::tempdir().expect("temporary directory should be created");
|
|
let source = root.path().join("source");
|
|
let destination = root.path().join("destination");
|
|
std::fs::create_dir(&source).expect("source directory should be created");
|
|
std::os::unix::fs::symlink(&source, &destination)
|
|
.expect("mount destination symlink should be created");
|
|
let descriptor = File::open(&source)
|
|
.expect("source directory descriptor should open")
|
|
.into_raw_fd();
|
|
let descriptor_path = format!("/proc/self/fd/{descriptor}");
|
|
let inherited = std::fs::metadata(&descriptor_path)
|
|
.expect("inherited descriptor metadata should be accessible");
|
|
let marker = format!("{descriptor}:{}", destination.display());
|
|
|
|
let error = verify_fd_mounts(&[marker]).expect_err("symlinked mounts must be rejected");
|
|
|
|
assert_eq!(error.kind(), std::io::ErrorKind::PermissionDenied);
|
|
assert_inherited_descriptor_closed(descriptor, &inherited);
|
|
}
|
|
|
|
/// Malformed mount markers cannot claim standard streams or relative destinations.
|
|
#[test]
|
|
fn malformed_mount_markers_are_rejected() {
|
|
for marker in [
|
|
"missing-separator",
|
|
"invalid:/tmp",
|
|
"0:/tmp",
|
|
"1:/tmp",
|
|
"2:/tmp",
|
|
] {
|
|
let error = verify_fd_mounts(&[marker.to_string()])
|
|
.expect_err("malformed mount marker must be rejected");
|
|
assert_eq!(error.kind(), std::io::ErrorKind::InvalidInput);
|
|
}
|
|
|
|
let root = tempfile::tempdir().expect("temporary directory should be created");
|
|
let descriptor = File::open(root.path())
|
|
.expect("directory descriptor should open")
|
|
.into_raw_fd();
|
|
let descriptor_path = format!("/proc/self/fd/{descriptor}");
|
|
let inherited = std::fs::metadata(&descriptor_path)
|
|
.expect("inherited descriptor metadata should be accessible");
|
|
let error = verify_fd_mounts(&[format!("{descriptor}:relative")])
|
|
.expect_err("relative mount destinations must be rejected");
|
|
|
|
assert_eq!(error.kind(), std::io::ErrorKind::InvalidInput);
|
|
assert_inherited_descriptor_closed(descriptor, &inherited);
|
|
}
|
|
|
|
/// A transferred descriptor can be consumed only once even if a marker is repeated.
|
|
#[test]
|
|
fn duplicate_mount_descriptors_are_rejected() {
|
|
let root = tempfile::tempdir().expect("temporary directory should be created");
|
|
let descriptor = File::open(root.path())
|
|
.expect("directory descriptor should open")
|
|
.into_raw_fd();
|
|
let descriptor_path = format!("/proc/self/fd/{descriptor}");
|
|
let inherited = std::fs::metadata(&descriptor_path)
|
|
.expect("inherited descriptor metadata should be accessible");
|
|
let marker = format!("{descriptor}:{}", root.path().display());
|
|
|
|
let error = verify_fd_mounts(&[marker.clone(), marker])
|
|
.expect_err("a mount descriptor must not be consumed twice");
|
|
|
|
assert_eq!(error.kind(), std::io::ErrorKind::InvalidInput);
|
|
assert_inherited_descriptor_closed(descriptor, &inherited);
|
|
}
|