From 104da7de12fe536ee100b87b9e86c81a5868a7e7 Mon Sep 17 00:00:00 2001 From: Red Bear OS Date: Mon, 13 Jul 2026 00:47:05 +0300 Subject: [PATCH] init: fix FILETABLE desync causing EEXIST on all daemon spawns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit create_pipe() used raw syscall::openat() (SYS_OPENAT) and syscall::dup() which bypass relibc's FILETABLE-managed fd allocation (SYS_OPENAT_INTO). This created phantom fds known to the kernel but not to relibc's userspace FILETABLE. When Command::spawn() later called relibc's pipe2() for fork+exec error reporting, the FILETABLE allocated a position it thought was free, but the kernel rejected it with EEXIST (errno 17). This killed EVERY daemon spawn during boot: logd, randd, zerod, rtcd, nulld, acpid, pcid, inputd, lived, redoxfs, pcid-spawner, fbcond, vesad, fbbootlogd, hwd, ps2d — all failed with 'File exists (os error 17)'. Fix: use libc::pipe2() which goes through relibc's FILETABLE-managed path (FdGuard::open → SYS_OPENAT_INTO), keeping tables in sync. --- init/src/service.rs | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/init/src/service.rs b/init/src/service.rs index d4f15baeda..2d5f94db92 100644 --- a/init/src/service.rs +++ b/init/src/service.rs @@ -37,25 +37,20 @@ pub enum ServiceType { } fn create_pipe() -> io::Result<(File, OwnedFd)> { - let ns_fd = libredox::call::getns() - .map_err(|e| io::Error::from_raw_os_error(e.errno()))?; - - let rd_fd = syscall::openat( - ns_fd, - "/scheme/pipe", - syscall::flag::O_RDONLY | syscall::flag::O_CLOEXEC, - 0, - ) - .map_err(|e| io::Error::from_raw_os_error(e.errno))?; - - let wr_raw = syscall::dup(rd_fd, b"write") - .map_err(|e| { - let _ = syscall::close(rd_fd); - io::Error::from_raw_os_error(e.errno) - })?; - - let wr = unsafe { OwnedFd::from_raw_fd(wr_raw as i32) }; - let rd = unsafe { File::from_raw_fd(rd_fd as i32) }; + let mut fds = [0; 2]; + // Use libc::pipe2() which goes through relibc's FILETABLE-managed path + // (FdGuard::open → SYS_OPENAT_INTO), keeping the userspace file table in + // sync with the kernel's file table. Using raw syscall::openat() + // (SYS_OPENAT) here would bypass the FILETABLE and create phantom fds + // that later cause EEXIST collisions when relibc's own pipe2() (called + // during Command::spawn fork+exec) tries to insert at a position the + // FILETABLE incorrectly thinks is free. + let ret = unsafe { libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC) }; + if ret != 0 { + return Err(io::Error::last_os_error()); + } + let rd = unsafe { File::from_raw_fd(fds[0]) }; + let wr = unsafe { OwnedFd::from_raw_fd(fds[1]) }; Ok((rd, wr)) }