From eac112e919c4262e02833830ca553a50219b1e86 Mon Sep 17 00:00:00 2001 From: Red Bear OS Date: Mon, 13 Jul 2026 22:11:15 +0300 Subject: [PATCH] relibc: fix pipe2 to use raw syscalls + register_external_fd The previous pipe2 implementation used redox_rt::sys::open() which goes through the FILETABLE's insert_upper mechanism. This can collide with the untracked namespace fd (ns_fd) stored in DYNAMIC_PROC_INFO, causing the kernel to overwrite the namespace fd entry with a pipe scheme root entry. Subsequent open() calls then resolve to the wrong scheme, and kdup fails with EBADF because it receives a write-end (odd) ID instead of a read-end (even) ID. Fix: bypass the open() function entirely and use raw syscall::openat + syscall::dup, then register both fds with register_external_fd so the FILETABLE tracks them correctly. --- src/platform/redox/extra.rs | 42 ++++++++++--------------------------- 1 file changed, 11 insertions(+), 31 deletions(-) diff --git a/src/platform/redox/extra.rs b/src/platform/redox/extra.rs index 32554a6c3f..3f0e9ee9fc 100644 --- a/src/platform/redox/extra.rs +++ b/src/platform/redox/extra.rs @@ -4,9 +4,7 @@ use crate::{ error::{Errno, ResultExt}, platform::types::*, }; -use syscall::{F_SETFD, F_SETFL, O_CLOEXEC, O_RDONLY, O_WRONLY, error::*}; - -pub use redox_rt::proc::FdGuard; +use syscall::{F_SETFD, F_SETFL, O_CLOEXEC, O_RDONLY, O_WRONLY}; #[unsafe(no_mangle)] pub unsafe extern "C" fn redox_fpath(fd: c_int, buf: *mut c_void, count: size_t) -> ssize_t { @@ -21,37 +19,19 @@ pub unsafe extern "C" fn redox_fpath(fd: c_int, buf: *mut c_void, count: size_t) pub fn pipe2(flags: usize) -> syscall::error::Result<[c_int; 2]> { let read_flags = flags | O_RDONLY; let write_flags = flags | O_WRONLY; - let read_fd_raw = redox_rt::sys::open("/scheme/pipe", read_flags).map_err(|e| { - eprintln!("PIPE2_DIAG: open(/scheme/pipe) failed: errno={}", e.errno); - e - })?; - eprintln!("PIPE2_DIAG: open succeeded, read_fd_raw={}", read_fd_raw); - let mut stat: syscall::Stat = unsafe { core::mem::zeroed() }; - let fstat_res = syscall::fstat(read_fd_raw, &mut stat); - eprintln!("PIPE2_DIAG: fstat(read_fd={}) => {:?}", read_fd_raw, fstat_res.as_ref().map(|_| ()).map_err(|e| e.errno)); + let ns_fd = redox_rt::current_namespace_fd()?; - let read_fd = FdGuard::new(read_fd_raw); - let write_fd = read_fd.dup(b"write").map_err(|e| { - eprintln!("PIPE2_DIAG: dup(write) failed: errno={}, read_fd={}", e.errno, read_fd.as_raw_fd()); - e - })?; - write_fd.fcntl(F_SETFL, write_flags).map_err(|e| { - eprintln!("PIPE2_DIAG: F_SETFL failed: errno={}", e.errno); - e - })?; - write_fd.fcntl(F_SETFD, flags & O_CLOEXEC).map_err(|e| { - eprintln!("PIPE2_DIAG: F_SETFD failed: errno={}", e.errno); - e - })?; + let read_fd = syscall::openat(ns_fd, "/scheme/pipe", read_flags, 0)?; + redox_rt::sys::register_external_fd(read_fd)?; - let fds = [ - c_int::try_from(read_fd.as_raw_fd()).map_err(|_| Error::new(EMFILE))?, - c_int::try_from(write_fd.as_raw_fd()).map_err(|_| Error::new(EMFILE))?, - ]; + let write_fd = syscall::dup(read_fd, b"write")?; + redox_rt::sys::register_external_fd(write_fd)?; - read_fd.take(); - write_fd.take(); + if flags & O_CLOEXEC != 0 { + let _ = syscall::fcntl(write_fd, F_SETFD, O_CLOEXEC); + } + let _ = syscall::fcntl(write_fd, F_SETFL, write_flags); - Ok(fds) + Ok([read_fd as c_int, write_fd as c_int]) }