From 0158b111e078950b46b003f3bd9f153fcc509669 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 9 Dec 2025 20:56:56 +0100 Subject: [PATCH 1/2] redox-rt: Use non-fixed and anonymous remote mmap --- redox-rt/src/proc.rs | 103 +++++++++++++++++-------------------- src/platform/redox/exec.rs | 4 -- 2 files changed, 48 insertions(+), 59 deletions(-) diff --git a/redox-rt/src/proc.rs b/redox-rt/src/proc.rs index 4819589c6f..5c41ac8241 100644 --- a/redox-rt/src/proc.rs +++ b/redox-rt/src/proc.rs @@ -68,7 +68,6 @@ pub fn fexec_impl( image_file: FdGuardUpper, thread_fd: &FdGuardUpper, proc_fd: &FdGuardUpper, - memory_scheme_fd: &FdGuardUpper, path: &[u8], args: &[&[u8]], envs: &[&[u8]], @@ -161,12 +160,12 @@ pub fn fexec_impl( return Err(Error::new(ENOEXEC)); } - allocate_remote( + mmap_anon_remote( &grants_fd, - memory_scheme_fd, + 0, vaddr, total_page_count * PAGE_SIZE, - flags, + flags | MapFlags::MAP_FIXED_NOREPLACE, )?; // TODO: Attempt to mmap with MAP_PRIVATE directly from the image file instead. @@ -202,12 +201,12 @@ pub fn fexec_impl( } } - allocate_remote( + mmap_anon_remote( &grants_fd, - memory_scheme_fd, + 0, STACK_TOP - STACK_SIZE, STACK_SIZE, - MapFlags::PROT_READ | MapFlags::PROT_WRITE, + MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::MAP_FIXED_NOREPLACE, )?; tree.insert(STACK_TOP - STACK_SIZE, STACK_SIZE); @@ -258,15 +257,14 @@ pub fn fexec_impl( &*phs_raw }; let pheaders_size_aligned = pheaders_to_convey.len().next_multiple_of(PAGE_SIZE); - let pheaders = find_free_target_addr(&tree, pheaders_size_aligned).ok_or(Error::new(ENOMEM))?; - tree.insert(pheaders, pheaders_size_aligned); - allocate_remote( + let pheaders = mmap_anon_remote( &grants_fd, - memory_scheme_fd, - pheaders, + 0, + 0, pheaders_size_aligned, MapFlags::PROT_READ | MapFlags::PROT_WRITE, )?; + tree.insert(pheaders, pheaders_size_aligned); unsafe { let (_guard, memory) = MmapGuard::map_mut_anywhere(&grants_fd, pheaders, pheaders_size_aligned)?; @@ -307,12 +305,10 @@ pub fn fexec_impl( + envs.iter().map(|env| env.len() + 1).sum::() + extrainfo.cwd.map_or(0, |s| s.len() + 1); let args_envs_size_aligned = total_args_envs_auxvpointee_size.next_multiple_of(PAGE_SIZE); - let target_args_env_address = - find_free_target_addr(&tree, args_envs_size_aligned).ok_or(Error::new(ENOMEM))?; - allocate_remote( + let target_args_env_address = mmap_anon_remote( &grants_fd, - memory_scheme_fd, - target_args_env_address, + 0, + 0, args_envs_size_aligned, MapFlags::PROT_READ | MapFlags::PROT_WRITE, )?; @@ -474,18 +470,8 @@ pub fn fexec_impl( unreachable!(); } -fn write_usizes(fd: &FdGuardUpper, usizes: [usize; N]) -> Result<()> { - fd.write(unsafe { plain::as_bytes(&usizes) })?; - Ok(()) -} -fn allocate_remote( - addrspace_fd: &FdGuardUpper, - memory_scheme_fd: &FdGuardUpper, - dst_addr: usize, - len: usize, - flags: MapFlags, -) -> Result<()> { - mmap_remote(addrspace_fd, memory_scheme_fd, 0, dst_addr, len, flags) +fn write_usizes(fd: &FdGuardUpper, usizes: [usize; N]) -> Result { + fd.write(unsafe { plain::as_bytes(&usizes) }) } pub fn mmap_remote( addrspace_fd: &FdGuardUpper, @@ -494,7 +480,7 @@ pub fn mmap_remote( dst_addr: usize, len: usize, flags: MapFlags, -) -> Result<()> { +) -> Result { write_usizes( addrspace_fd, [ @@ -509,7 +495,32 @@ pub fn mmap_remote( // size len, // flags - (flags | MapFlags::MAP_FIXED_NOREPLACE).bits(), + flags.bits(), + ], + ) +} +pub fn mmap_anon_remote( + addrspace_fd: &FdGuardUpper, + offset: usize, + dst_addr: usize, + len: usize, + flags: MapFlags, +) -> Result { + write_usizes( + addrspace_fd, + [ + // op + syscall::flag::ADDRSPACE_OP_MMAP, + // fd + !0, + // "offset" + offset, + // address + dst_addr, + // size + len, + // flags + flags.bits(), ], ) } @@ -531,7 +542,8 @@ pub fn mprotect_remote( // flags flags.bits(), ], - ) + )?; + Ok(()) } pub fn munmap_remote(addrspace_fd: &FdGuardUpper, addr: usize, len: usize) -> Result<()> { write_usizes( @@ -544,7 +556,8 @@ pub fn munmap_remote(addrspace_fd: &FdGuardUpper, addr: usize, len: usize) -> Re // size len, ], - ) + )?; + Ok(()) } pub fn munmap_transfer( src: &FdGuardUpper, @@ -570,7 +583,8 @@ pub fn munmap_transfer( // flags (flags | MapFlags::MAP_FIXED_NOREPLACE).bits(), ], - ) + )?; + Ok(()) } fn pread_all(fd: &FdGuardUpper, offset: u64, buf: &mut [u8]) -> Result<()> { fd.lseek(offset as isize, SEEK_SET)?; @@ -586,27 +600,6 @@ fn pread_all(fd: &FdGuardUpper, offset: u64, buf: &mut [u8]) -> Result<()> { Ok(()) } -// TODO: With the introduction of remote mmaps, remove this and let the kernel handle address -// allocation. -fn find_free_target_addr(tree: &BTreeMap, size: usize) -> Option { - let mut iterator = tree.iter().peekable(); - - // Ignore the space between zero and the first region, to avoid null pointers. - while let Some((cur_address, entry_size)) = iterator.next() { - let end = *cur_address + entry_size; - - if let Some((next_address, _)) = iterator.peek() { - if **next_address - end > size { - return Some(end); - } - } - // No need to check last entry, since the stack will always be put at the highest - // possible address. - } - - None -} - pub struct MmapGuard<'a> { fd: &'a FdGuardUpper, base: usize, diff --git a/src/platform/redox/exec.rs b/src/platform/redox/exec.rs index 2979e5f84c..0fe66ea7df 100644 --- a/src/platform/redox/exec.rs +++ b/src/platform/redox/exec.rs @@ -29,8 +29,6 @@ fn fexec_impl( extrainfo: &ExtraInfo, interp_override: Option, ) -> Result { - let memory = FdGuard::open("/scheme/memory", O_CLOEXEC)?.to_upper()?; - let FexecResult::Interp { image_file, path, @@ -39,7 +37,6 @@ fn fexec_impl( exec_file, &RtTcb::current().thread_fd(), redox_rt::current_proc_fd(), - &memory, path, args, envs, @@ -48,7 +45,6 @@ fn fexec_impl( )?; drop(image_file); - drop(memory); // According to elf(5), PT_INTERP requires that the interpreter path be // null-terminated. Violating this should therefore give the "format error" ENOEXEC. From c96aeea39fe708f38b1820bd60f543d259dec3f7 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 9 Dec 2025 21:03:01 +0100 Subject: [PATCH 2/2] redox-rt: Get rid of BTreeMap usage in fexec_impl --- redox-rt/src/proc.rs | 37 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/redox-rt/src/proc.rs b/redox-rt/src/proc.rs index 5c41ac8241..17e3975298 100644 --- a/redox-rt/src/proc.rs +++ b/redox-rt/src/proc.rs @@ -1,5 +1,6 @@ use core::{ cell::SyncUnsafeCell, + cmp, fmt::Debug, mem::{MaybeUninit, size_of}, }; @@ -13,7 +14,7 @@ use crate::{ sys::{proc_call, thread_call}, }; -use alloc::{boxed::Box, collections::BTreeMap, vec}; +use alloc::{boxed::Box, vec}; //TODO: allow use of either 32-bit or 64-bit programs #[cfg(target_pointer_width = "32")] @@ -47,7 +48,6 @@ pub struct InterpOverride { at_phnum: usize, at_phent: usize, name: Box<[u8]>, - tree: BTreeMap, } pub struct ExtraInfo<'a> { @@ -72,7 +72,7 @@ pub fn fexec_impl( args: &[&[u8]], envs: &[&[u8]], extrainfo: &ExtraInfo, - mut interp_override: Option, + interp_override: Option, ) -> Result { // Here, we do the minimum part of loading an application, which is what the kernel used to do. // We load the executable into memory (albeit at different offsets in this executable), fix @@ -103,10 +103,10 @@ pub fn fexec_impl( let phs = &mut phs_raw[size_of::
()..]; // TODO: Remove clone, but this would require more as_refs and as_muts - let mut tree = interp_override.as_mut().map_or_else( - || core::iter::once((0, PAGE_SIZE)).collect::>(), - |o| core::mem::take(&mut o.tree), - ); + let mut min_mmap_addr = PAGE_SIZE; + let mut update_min_mmap_addr = |addr: usize, size: usize| { + min_mmap_addr = cmp::min(min_mmap_addr, (addr + size).next_multiple_of(PAGE_SIZE)); + }; pread_all(&image_file, u64::from(header.e_phoff), phs).map_err(|_| Error::new(EIO))?; @@ -142,7 +142,6 @@ pub fn fexec_impl( at_phent: phentsize, phs: phs_raw.into_boxed_slice(), name: path.into(), - tree, }, }); } @@ -185,17 +184,7 @@ pub fn fexec_impl( )?; } - // file_page_count..file_page_count + zero_page_count are already zero-initialized - // by the kernel. - - if !tree - .range(..=vaddr) - .next_back() - .filter(|(start, size)| **start + **size > vaddr) - .is_some() - { - tree.insert(vaddr, total_page_count * PAGE_SIZE); - } + update_min_mmap_addr(vaddr, total_page_count * PAGE_SIZE); } _ => continue, } @@ -208,7 +197,7 @@ pub fn fexec_impl( STACK_SIZE, MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::MAP_FIXED_NOREPLACE, )?; - tree.insert(STACK_TOP - STACK_SIZE, STACK_SIZE); + update_min_mmap_addr(STACK_TOP - STACK_SIZE, STACK_SIZE); let mut sp = STACK_TOP; let mut stack_page = Option::::None; @@ -264,7 +253,7 @@ pub fn fexec_impl( pheaders_size_aligned, MapFlags::PROT_READ | MapFlags::PROT_WRITE, )?; - tree.insert(pheaders, pheaders_size_aligned); + update_min_mmap_addr(pheaders, pheaders_size_aligned); unsafe { let (_guard, memory) = MmapGuard::map_mut_anywhere(&grants_fd, pheaders, pheaders_size_aligned)?; @@ -312,7 +301,7 @@ pub fn fexec_impl( args_envs_size_aligned, MapFlags::PROT_READ | MapFlags::PROT_WRITE, )?; - tree.insert(target_args_env_address, args_envs_size_aligned); + update_min_mmap_addr(target_args_env_address, args_envs_size_aligned); let mut offset = 0; @@ -421,9 +410,7 @@ pub fn fexec_impl( if interp_override.is_some() { let mmap_min_fd = grants_fd.dup(b"mmap-min-addr")?; - let last_addr = tree.iter().rev().nth(1).map_or(0, |(off, len)| *off + *len); - let aligned_last_addr = last_addr.next_multiple_of(PAGE_SIZE); - let _ = mmap_min_fd.write(&usize::to_ne_bytes(aligned_last_addr)); + let _ = mmap_min_fd.write(&usize::to_ne_bytes(min_mmap_addr)); } let addrspace_selection_fd = thread_fd.dup(b"current-addrspace")?.to_upper()?;