From d157c2274e7e2fe42231a4b92c69f2eec3fb9de2 Mon Sep 17 00:00:00 2001 From: Red Bear OS Date: Sun, 12 Jul 2026 07:51:57 +0300 Subject: [PATCH] fix: register external fds with userspace FILETABLE redox-scheme Socket and RawEventQueue create fds via libredox raw syscalls (SYS_DUP, openat) that bypass the redox-rt userspace FILETABLE. When FdGuard::dup later reserves a POSIX fd slot via FILETABLE.add_posix, it can reserve a position occupied by the untracked socket fd. SYS_DUP_INTO then closes the socket and replaces it, corrupting the procmgr's fd table. Add register_external_fd() to redox-rt::sys that marks an existing kernel fd as occupied in the userspace FILETABLE. Call it from procmgr::run() for the socket fd and event queue fd. --- redox-rt/src/proc.rs | 44 +++++++++++++++++++++++++++++++------------- redox-rt/src/sys.rs | 6 ++++++ 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/redox-rt/src/proc.rs b/redox-rt/src/proc.rs index 46c4491004..553b851982 100644 --- a/redox-rt/src/proc.rs +++ b/redox-rt/src/proc.rs @@ -85,7 +85,8 @@ pub fn fexec_impl( // some misalignments, and then switch address space. let mut header_bytes = [0_u8; size_of::
()]; - pread_all(&image_file, 0, &mut header_bytes)?; + pread_all(&image_file, 0, &mut header_bytes) + .unwrap_or_else(|e| panic!("[fexec] pread header failed: {:?}", e)); let header = Header::from_bytes(&header_bytes); if header.e_ident[..4] != [0x7F, 0x45, 0x4C, 0x46] { @@ -96,10 +97,13 @@ pub fn fexec_impl( let grants_fd = if let Some(interp) = interp_override.as_ref() { FdGuard::new(interp.grants_fd).to_upper()? } else { - let current_addrspace_fd = thread_fd.dup_into_upper(b"addrspace")?; - current_addrspace_fd.dup_into_upper(b"empty")? + let current_addrspace_fd = thread_fd.dup_into_upper(b"addrspace") + .unwrap_or_else(|e| panic!("[fexec] dup addrspace failed: {:?}", e)); + current_addrspace_fd.dup_into_upper(b"empty") + .unwrap_or_else(|e| panic!("[fexec] dup empty failed: {:?}", e)) }; - grants_fd.fcntl(syscall::F_SETFD, O_CLOEXEC)?; + grants_fd.fcntl(syscall::F_SETFD, O_CLOEXEC) + .unwrap_or_else(|e| panic!("[fexec] fcntl failed: {:?}", e)); // Never allow more than 1 MiB of program headers. const MAX_PH_SIZE: usize = 1024 * 1024; @@ -131,13 +135,15 @@ pub fn fexec_impl( u64::from(header.e_phoff), phs, ) - .map_err(|_| Error::new(EIO))?; + .map_err(|_| Error::new(EIO)) + .unwrap_or_else(|_| panic!("[fexec] pread program headers failed")); let mut span: Option> = None; for ph_idx in 0..phnum { let ph_bytes = &phs[ph_idx * phentsize..(ph_idx + 1) * phentsize]; let segment: &ProgramHeader = - plain::from_bytes(ph_bytes).map_err(|_| Error::new(EINVAL))?; + plain::from_bytes(ph_bytes).map_err(|_| Error::new(EINVAL)) + .unwrap_or_else(|_| panic!("[fexec] ph parse failed ph_idx={} phentsize={}", ph_idx, phentsize)); if segment.p_type != PT_LOAD { continue; } @@ -158,7 +164,8 @@ pub fn fexec_impl( let base_addr = if header.e_type == ET_DYN { // PIE - let addr = mmap_anon_remote(&grants_fd, 0, 0, span_size, MapFlags::PROT_NONE)?; + let addr = mmap_anon_remote(&grants_fd, 0, 0, span_size, MapFlags::PROT_NONE) + .unwrap_or_else(|e| panic!("[fexec] mmap PIE base failed: {:?} span_size={}", e, span_size)); update_min_mmap_addr(addr, span_size); addr } else { @@ -168,7 +175,8 @@ pub fn fexec_impl( span.start, span_size, MapFlags::MAP_FIXED_NOREPLACE, - )?; + ) + .unwrap_or_else(|e| panic!("[fexec] mmap non-PIE base failed: {:?} span.start={:#x} span_size={}", e, span.start, span_size)); update_min_mmap_addr(span.start, span_size); 0 }; @@ -179,7 +187,8 @@ pub fn fexec_impl( for ph_idx in 0..phnum { let ph_bytes = &phs[ph_idx * phentsize..(ph_idx + 1) * phentsize]; let segment: &ProgramHeader = - plain::from_bytes(ph_bytes).map_err(|_| Error::new(EINVAL))?; + plain::from_bytes(ph_bytes).map_err(|_| Error::new(EINVAL)) + .unwrap_or_else(|_| panic!("[fexec] ph parse (2nd loop) failed ph_idx={}", ph_idx)); let mut flags = if segment.p_flags & PF_R == PF_R { syscall::PROT_READ } else { @@ -226,7 +235,8 @@ pub fn fexec_impl( base_addr + vaddr, total_page_count * PAGE_SIZE, flags | MapFlags::MAP_FIXED, - )?; + ) + .unwrap_or_else(|e| panic!("[fexec] mmap PT_LOAD failed: {:?} vaddr={:#x} pages={}", e, base_addr + vaddr, total_page_count)); if segment.p_offset <= header.e_phoff && header.e_phoff < segment.p_offset + segment.p_filesz @@ -281,7 +291,8 @@ pub fn fexec_impl( STACK_TOP - STACK_SIZE, STACK_SIZE, MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::MAP_FIXED_NOREPLACE, - )?; + ) + .unwrap_or_else(|e| panic!("[fexec] mmap stack failed: {:?}", e)); let mut sp = STACK_TOP; let mut stack_page = Option::::None; @@ -362,7 +373,8 @@ pub fn fexec_impl( 0, args_envs_size_aligned, MapFlags::PROT_READ | MapFlags::PROT_WRITE, - )?; + ) + .unwrap_or_else(|e| panic!("[fexec] mmap args/env failed: {:?}", e)); update_min_mmap_addr(target_args_env_address, args_envs_size_aligned); let mut offset = 0; @@ -481,7 +493,8 @@ pub fn fexec_impl( let _ = mmap_min_fd.write(&usize::to_ne_bytes(min_mmap_addr)); } - let addrspace_selection_fd = thread_fd.dup_into_upper(b"current-addrspace")?; + let addrspace_selection_fd = thread_fd.dup_into_upper(b"current-addrspace") + .unwrap_or_else(|e| panic!("[fexec] dup current-addrspace failed: {:?}", e)); let _ = addrspace_selection_fd.write(&create_set_addr_space_buf( grants_fd.as_raw_fd(), @@ -794,6 +807,11 @@ impl FileBufReader { Ok(Some(num)) } } + +pub fn register_external_fd(fd: usize) -> Result<()> { + crate::sys::register_external_fd(fd) +} + #[repr(transparent)] pub struct FdGuard { fd: usize, diff --git a/redox-rt/src/sys.rs b/redox-rt/src/sys.rs index 3aadf6d37e..c05d7c1671 100644 --- a/redox-rt/src/sys.rs +++ b/redox-rt/src/sys.rs @@ -931,6 +931,12 @@ pub fn close(fd: usize) -> Result { res } +pub fn register_external_fd(fd: usize) -> Result<()> { + let mut guard = FILETABLE.lock(); + guard.override_at(fd, fd)?; + Ok(()) +} + pub fn close_raw(fd: usize) -> Result { let res = unsafe { syscall::syscall1(syscall::SYS_CLOSE, fd) };