relibc: fix open() to bypass FILETABLE.insert_upper collision
The open() function used openat_into_upper which calls FILETABLE.insert_upper() to allocate UPPER fd slots. This can collide with the namespace fd (ns_fd) that is stored in DYNAMIC_PROC_INFO, causing the kernel to overwrite the namespace fd entry. All subsequent open() calls then resolve to the wrong scheme. Fix: use raw SYS_OPENAT syscalls (which auto-assign POSIX fds) and register them with register_external_fd, bypassing insert_upper entirely.
This commit is contained in:
+23
-4
@@ -592,13 +592,32 @@ pub fn open<T: AsRef<str>>(path: T, flags: usize) -> Result<usize> {
|
||||
let fcntl_flags = flags & syscall::O_FCNTL_MASK;
|
||||
let redox_path = RedoxPath::from_absolute(path.as_ref()).ok_or(Error::new(EINVAL))?;
|
||||
let (_, reference) = redox_path.as_parts().ok_or(Error::new(EINVAL))?;
|
||||
let root_fd = FdGuard::new(openat_into_upper(
|
||||
crate::current_namespace_fd()?,
|
||||
|
||||
let ns_fd = crate::current_namespace_fd()?;
|
||||
|
||||
// Open the scheme root using raw SYS_OPENAT (auto-assigned POSIX fd).
|
||||
// This bypasses FILETABLE.insert_upper, which could collide with the
|
||||
// namespace fd (ns_fd) that is not always tracked in the UPPER table.
|
||||
let root_fd = syscall::openat(
|
||||
ns_fd,
|
||||
path.as_ref(),
|
||||
syscall::O_DIRECTORY | O_CLOEXEC,
|
||||
0,
|
||||
)?);
|
||||
openat_into_posix(root_fd.as_raw_fd(), reference.as_ref(), flags, fcntl_flags)
|
||||
)?;
|
||||
register_external_fd(root_fd)?;
|
||||
|
||||
let posix_fd = syscall::openat(
|
||||
root_fd,
|
||||
reference.as_ref(),
|
||||
flags,
|
||||
fcntl_flags,
|
||||
)?;
|
||||
|
||||
// Close root_fd and remove from FILETABLE, then register posix_fd.
|
||||
close(root_fd)?;
|
||||
register_external_fd(posix_fd)?;
|
||||
|
||||
Ok(posix_fd)
|
||||
}
|
||||
pub fn openat<T: AsRef<str>>(
|
||||
fd: usize,
|
||||
|
||||
Reference in New Issue
Block a user