Ver Fonte

Use better interfaces in exec/clone

4lDO2 há 2 anos atrás
pai
commit
985b2a59a9

+ 3 - 13
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<usize> {
                 }
                 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::<usize>() * 4];
-                let mut chunks = buf.array_chunks_mut::<{size_of::<usize>()}>();
-                *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")?);
 

+ 4 - 1
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);

+ 1 - 1
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,
 };
 

+ 69 - 13
src/platform/redox/redox-exec/src/lib.rs

@@ -33,7 +33,7 @@ pub struct InterpOverride {
     tree: BTreeMap<usize, usize>,
 }
 
-pub fn fexec_impl<A, E>(image_file: FdGuard, open_via_dup: FdGuard, path: &[u8], args: A, envs: E, total_args_envs_size: usize, mut interp_override: Option<InterpOverride>) -> Result<FexecResult>
+pub fn fexec_impl<A, E>(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<InterpOverride>) -> Result<FexecResult>
 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<const N: usize>(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<u64>, 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<u64>, 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<usize, usize>, size: usize) -> Option<usize> {
     let mut iterator = tree.iter().peekable();