From 985b2a59a92682f3cb447d3385d96b37390838b3 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 26 Jul 2022 15:50:00 +0200 Subject: [PATCH] Use better interfaces in exec/clone --- src/platform/redox/clone.rs | 16 +---- src/platform/redox/exec.rs | 5 +- src/platform/redox/mod.rs | 2 +- src/platform/redox/redox-exec/src/lib.rs | 82 ++++++++++++++++++++---- 4 files changed, 77 insertions(+), 28 deletions(-) diff --git a/src/platform/redox/clone.rs b/src/platform/redox/clone.rs index 45060f54da..4fcf0576bf 100644 --- a/src/platform/redox/clone.rs +++ b/src/platform/redox/clone.rs @@ -33,6 +33,7 @@ fn copy_str(cur_pid_fd: usize, new_pid_fd: usize, key: &str) -> Result<()> { let cur_name_fd = FdGuard::new(syscall::dup(cur_pid_fd, key.as_bytes())?); let new_name_fd = FdGuard::new(syscall::dup(new_pid_fd, key.as_bytes())?); + // TODO: Max path size? let mut buf = [0_u8; 256]; let len = syscall::read(*cur_name_fd, &mut buf)?; let buf = buf.get(..len).ok_or(Error::new(ENAMETOOLONG))?; @@ -194,19 +195,8 @@ fn fork_inner(initial_rsp: *mut usize) -> Result { } let map_flags = MapFlags::from_bits_truncate(flags); - let mapped_address = unsafe { - let fd = FdGuard::new(syscall::dup(*cur_addr_space_fd, format!("grant-{:x}", addr).as_bytes())?); - syscall::fmap(*fd, &syscall::Map { address: 0, size, flags: map_flags, offset })? - }; - - let mut buf = [0_u8; size_of::() * 4]; - let mut chunks = buf.array_chunks_mut::<{size_of::()}>(); - *chunks.next().unwrap() = usize::to_ne_bytes(addr); - *chunks.next().unwrap() = usize::to_ne_bytes(size); - *chunks.next().unwrap() = usize::to_ne_bytes(map_flags.bits()); - *chunks.next().unwrap() = usize::to_ne_bytes(mapped_address); - - let _ = syscall::write(*new_addr_space_fd, &buf)?; + let grant_fd = FdGuard::new(syscall::dup(*cur_addr_space_fd, format!("grant-{:x}", addr).as_bytes())?); + redox_exec::mmap_remote(&new_addr_space_fd, &grant_fd, offset, addr, size, map_flags)?; } let new_addr_space_sel_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"current-addrspace")?); diff --git a/src/platform/redox/exec.rs b/src/platform/redox/exec.rs index c551eb3133..99b561c684 100644 --- a/src/platform/redox/exec.rs +++ b/src/platform/redox/exec.rs @@ -15,12 +15,14 @@ fn fexec_impl(file: File, path: &[u8], args: &[&[u8]], envs: &[&[u8]], total_arg let image_file = FdGuard::new(fd as usize); let open_via_dup = FdGuard::new(syscall::open("thisproc:current/open_via_dup", 0)?); + let memory = FdGuard::new(syscall::open("memory:", 0)?); - let addrspace_selection_fd = match redox_exec::fexec_impl(image_file, open_via_dup, path, args.iter().rev(), envs.iter().rev(), total_args_envs_size, interp_override)? { + let addrspace_selection_fd = match redox_exec::fexec_impl(image_file, open_via_dup, &memory, path, args.iter().rev(), envs.iter().rev(), total_args_envs_size, interp_override)? { FexecResult::Normal { addrspace_handle } => addrspace_handle, FexecResult::Interp { image_file, open_via_dup, path, interp_override: new_interp_override } => { drop(image_file); drop(open_via_dup); + 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. @@ -29,6 +31,7 @@ fn fexec_impl(file: File, path: &[u8], args: &[&[u8]], envs: &[&[u8]], total_arg return execve(path_cstr, ArgEnv::Parsed { total_args_envs_size, args, envs }, Some(new_interp_override)); } }; + drop(memory); // Dropping this FD will cause the address space switch. drop(addrspace_selection_fd); diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 67c9392e71..4f41c6d76e 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -3,7 +3,7 @@ use core::arch::asm; use syscall::{ self, - data::{CloneInfo, Map, Stat as redox_stat, StatVfs as redox_statvfs, TimeSpec as redox_timespec}, + data::{Map, Stat as redox_stat, StatVfs as redox_statvfs, TimeSpec as redox_timespec}, PtraceEvent, Result, }; diff --git a/src/platform/redox/redox-exec/src/lib.rs b/src/platform/redox/redox-exec/src/lib.rs index 1146b0ede0..658f524bba 100644 --- a/src/platform/redox/redox-exec/src/lib.rs +++ b/src/platform/redox/redox-exec/src/lib.rs @@ -33,7 +33,7 @@ pub struct InterpOverride { tree: BTreeMap, } -pub fn fexec_impl(image_file: FdGuard, open_via_dup: FdGuard, path: &[u8], args: A, envs: E, total_args_envs_size: usize, mut interp_override: Option) -> Result +pub fn fexec_impl(image_file: FdGuard, open_via_dup: FdGuard, memory_scheme_fd: &FdGuard, path: &[u8], args: A, envs: E, total_args_envs_size: usize, mut interp_override: Option) -> Result where A: IntoIterator, E: IntoIterator, @@ -122,7 +122,7 @@ where }); } PT_LOAD => { - mprotect_remote(*grants_fd, vaddr, size, flags)?; + allocate_remote(&grants_fd, memory_scheme_fd, vaddr, size, syscall::PROT_READ | syscall::PROT_WRITE)?; syscall::lseek(*image_file as usize, segment.p_offset as isize, SEEK_SET).map_err(|_| Error::new(EIO))?; syscall::lseek(*memory_fd, segment.p_vaddr as isize, SEEK_SET).map_err(|_| Error::new(EIO))?; @@ -130,6 +130,7 @@ where read_all(*image_file as usize, None, &mut buf[..size]).map_err(|_| Error::new(EIO))?; let _ = syscall::write(*memory_fd, &buf[..size]).map_err(|_| Error::new(EIO))?; } + mprotect_remote(&grants_fd, vaddr, size, flags)?; if !tree.range(..=vaddr).next_back().filter(|(start, size)| **start + **size > vaddr).is_some() { tree.insert(vaddr, size); @@ -142,7 +143,7 @@ where const STACK_TOP: usize = 1 << 47; const STACK_SIZE: usize = 1024 * 1024; - mprotect_remote(*grants_fd, STACK_TOP - STACK_SIZE, STACK_SIZE, MapFlags::PROT_READ | MapFlags::PROT_WRITE)?; + allocate_remote(&grants_fd, memory_scheme_fd, STACK_TOP - STACK_SIZE, STACK_SIZE, MapFlags::PROT_READ | MapFlags::PROT_WRITE)?; tree.insert(STACK_TOP - STACK_SIZE, STACK_SIZE); let mut sp = STACK_TOP - 256; @@ -160,9 +161,9 @@ where let pheaders_size_aligned = (pheaders_to_convey.len()+PAGE_SIZE-1)/PAGE_SIZE*PAGE_SIZE; let pheaders = find_free_target_addr(&tree, pheaders_size_aligned).ok_or(Error::new(ENOMEM))?; tree.insert(pheaders, pheaders_size_aligned); - mprotect_remote(*grants_fd, pheaders, pheaders_size_aligned, MapFlags::PROT_READ)?; - + allocate_remote(&grants_fd, memory_scheme_fd, pheaders, pheaders_size_aligned, MapFlags::PROT_READ | MapFlags::PROT_WRITE)?; write_all(*memory_fd, Some(pheaders as u64), &pheaders_to_convey)?; + mprotect_remote(&grants_fd, pheaders, pheaders_size_aligned, MapFlags::PROT_READ)?; push(0)?; push(AT_NULL)?; @@ -181,7 +182,7 @@ where let args_envs_size_aligned = (total_args_envs_size+PAGE_SIZE-1)/PAGE_SIZE*PAGE_SIZE; let target_args_env_address = find_free_target_addr(&tree, args_envs_size_aligned).ok_or(Error::new(ENOMEM))?; - mprotect_remote(*grants_fd, target_args_env_address, args_envs_size_aligned, MapFlags::PROT_READ | MapFlags::PROT_WRITE)?; + allocate_remote(&grants_fd, memory_scheme_fd, target_args_env_address, args_envs_size_aligned, MapFlags::PROT_READ | MapFlags::PROT_WRITE)?; tree.insert(target_args_env_address, args_envs_size_aligned); let mut offset = 0; @@ -226,7 +227,7 @@ where if let Ok(name_fd) = syscall::dup(*open_via_dup, b"name").map(FdGuard::new) { let _ = syscall::write(*name_fd, interp_override.as_ref().map_or(path, |o| &o.name)); } - { + if interp_override.is_some() { let mmap_min_fd = FdGuard::new(syscall::dup(*open_via_dup, b"mmap-min-addr")?); let _ = syscall::write(*mmap_min_fd, &usize::to_ne_bytes(tree.iter().rev().nth(1).map_or(0, |(off, len)| *off + *len))); } @@ -237,14 +238,67 @@ where Ok(FexecResult::Normal { addrspace_handle: addrspace_selection_fd }) } -fn mprotect_remote(socket: usize, addr: usize, len: usize, flags: MapFlags) -> Result<()> { - let mut grants_buf = [0_u8; 24]; - grants_buf[..8].copy_from_slice(&usize::to_ne_bytes(addr)); - grants_buf[8..16].copy_from_slice(&usize::to_ne_bytes(len)); - grants_buf[16..24].copy_from_slice(&usize::to_ne_bytes(flags.bits())); - syscall::write(socket, &grants_buf)?; +fn write_usizes(fd: &FdGuard, usizes: [usize; N]) -> Result<()> { + let _ = syscall::write(**fd, unsafe { plain::as_bytes(&usizes) }); Ok(()) } +fn allocate_remote(addrspace_fd: &FdGuard, memory_scheme_fd: &FdGuard, dst_addr: usize, len: usize, flags: MapFlags) -> Result<()> { + mmap_remote(addrspace_fd, memory_scheme_fd, 0, dst_addr, len, flags) +} +pub fn mmap_remote(addrspace_fd: &FdGuard, fd: &FdGuard, offset: usize, dst_addr: usize, len: usize, flags: MapFlags) -> Result<()> { + write_usizes(addrspace_fd, [ + // op + syscall::flag::ADDRSPACE_OP_MMAP, + // fd + **fd, + // "offset" + offset, + // address + dst_addr, + // size + len, + // flags + (flags | MapFlags::MAP_FIXED_NOREPLACE).bits(), + ]) +} +pub fn mprotect_remote(addrspace_fd: &FdGuard, addr: usize, len: usize, flags: MapFlags) -> Result<()> { + write_usizes(addrspace_fd, [ + // op + syscall::flag::ADDRSPACE_OP_MPROTECT, + // address + addr, + // size + len, + // flags + flags.bits(), + ]) +} +pub fn munmap_remote(addrspace_fd: &FdGuard, addr: usize, len: usize) -> Result<()> { + write_usizes(addrspace_fd, [ + // op + syscall::flag::ADDRSPACE_OP_MUNMAP, + // address + addr, + // size + len, + ]) +} +pub fn munmap_transfer(src: &FdGuard, dst: &FdGuard, src_addr: usize, dst_addr: usize, len: usize, flags: MapFlags) -> Result<()> { + write_usizes(dst, [ + // op + syscall::flag::ADDRSPACE_OP_TRANSFER, + // fd + **src, + // "offset" (source address) + src_addr, + // address + dst_addr, + // size + len, + // flags + (flags | MapFlags::MAP_FIXED_NOREPLACE).bits(), + ]) +} fn read_all(fd: usize, offset: Option, buf: &mut [u8]) -> Result<()> { if let Some(offset) = offset { syscall::lseek(fd, offset as isize, SEEK_SET)?; @@ -276,6 +330,8 @@ fn write_all(fd: usize, offset: Option, buf: &[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();